162306a36Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 262306a36Sopenharmony_ci/* Copyright (c) 2017-2018 Mellanox Technologies. All rights reserved */ 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#include <linux/kernel.h> 562306a36Sopenharmony_ci#include <linux/mutex.h> 662306a36Sopenharmony_ci#include <net/devlink.h> 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include "spectrum.h" 962306a36Sopenharmony_ci#include "spectrum_dpipe.h" 1062306a36Sopenharmony_ci#include "spectrum_router.h" 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_cienum mlxsw_sp_field_metadata_id { 1362306a36Sopenharmony_ci MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT, 1462306a36Sopenharmony_ci MLXSW_SP_DPIPE_FIELD_METADATA_L3_FORWARD, 1562306a36Sopenharmony_ci MLXSW_SP_DPIPE_FIELD_METADATA_L3_DROP, 1662306a36Sopenharmony_ci MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_INDEX, 1762306a36Sopenharmony_ci MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_SIZE, 1862306a36Sopenharmony_ci MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_HASH_INDEX, 1962306a36Sopenharmony_ci}; 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_cistatic struct devlink_dpipe_field mlxsw_sp_dpipe_fields_metadata[] = { 2262306a36Sopenharmony_ci { 2362306a36Sopenharmony_ci .name = "erif_port", 2462306a36Sopenharmony_ci .id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT, 2562306a36Sopenharmony_ci .bitwidth = 32, 2662306a36Sopenharmony_ci .mapping_type = DEVLINK_DPIPE_FIELD_MAPPING_TYPE_IFINDEX, 2762306a36Sopenharmony_ci }, 2862306a36Sopenharmony_ci { 2962306a36Sopenharmony_ci .name = "l3_forward", 3062306a36Sopenharmony_ci .id = MLXSW_SP_DPIPE_FIELD_METADATA_L3_FORWARD, 3162306a36Sopenharmony_ci .bitwidth = 1, 3262306a36Sopenharmony_ci }, 3362306a36Sopenharmony_ci { 3462306a36Sopenharmony_ci .name = "l3_drop", 3562306a36Sopenharmony_ci .id = MLXSW_SP_DPIPE_FIELD_METADATA_L3_DROP, 3662306a36Sopenharmony_ci .bitwidth = 1, 3762306a36Sopenharmony_ci }, 3862306a36Sopenharmony_ci { 3962306a36Sopenharmony_ci .name = "adj_index", 4062306a36Sopenharmony_ci .id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_INDEX, 4162306a36Sopenharmony_ci .bitwidth = 32, 4262306a36Sopenharmony_ci }, 4362306a36Sopenharmony_ci { 4462306a36Sopenharmony_ci .name = "adj_size", 4562306a36Sopenharmony_ci .id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_SIZE, 4662306a36Sopenharmony_ci .bitwidth = 32, 4762306a36Sopenharmony_ci }, 4862306a36Sopenharmony_ci { 4962306a36Sopenharmony_ci .name = "adj_hash_index", 5062306a36Sopenharmony_ci .id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_HASH_INDEX, 5162306a36Sopenharmony_ci .bitwidth = 32, 5262306a36Sopenharmony_ci }, 5362306a36Sopenharmony_ci}; 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_cienum mlxsw_sp_dpipe_header_id { 5662306a36Sopenharmony_ci MLXSW_SP_DPIPE_HEADER_METADATA, 5762306a36Sopenharmony_ci}; 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_cistatic struct devlink_dpipe_header mlxsw_sp_dpipe_header_metadata = { 6062306a36Sopenharmony_ci .name = "mlxsw_meta", 6162306a36Sopenharmony_ci .id = MLXSW_SP_DPIPE_HEADER_METADATA, 6262306a36Sopenharmony_ci .fields = mlxsw_sp_dpipe_fields_metadata, 6362306a36Sopenharmony_ci .fields_count = ARRAY_SIZE(mlxsw_sp_dpipe_fields_metadata), 6462306a36Sopenharmony_ci}; 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_cistatic struct devlink_dpipe_header *mlxsw_dpipe_headers[] = { 6762306a36Sopenharmony_ci &mlxsw_sp_dpipe_header_metadata, 6862306a36Sopenharmony_ci &devlink_dpipe_header_ethernet, 6962306a36Sopenharmony_ci &devlink_dpipe_header_ipv4, 7062306a36Sopenharmony_ci &devlink_dpipe_header_ipv6, 7162306a36Sopenharmony_ci}; 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_cistatic struct devlink_dpipe_headers mlxsw_sp_dpipe_headers = { 7462306a36Sopenharmony_ci .headers = mlxsw_dpipe_headers, 7562306a36Sopenharmony_ci .headers_count = ARRAY_SIZE(mlxsw_dpipe_headers), 7662306a36Sopenharmony_ci}; 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_cistatic int mlxsw_sp_dpipe_table_erif_actions_dump(void *priv, 7962306a36Sopenharmony_ci struct sk_buff *skb) 8062306a36Sopenharmony_ci{ 8162306a36Sopenharmony_ci struct devlink_dpipe_action action = {0}; 8262306a36Sopenharmony_ci int err; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci action.type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY; 8562306a36Sopenharmony_ci action.header = &mlxsw_sp_dpipe_header_metadata; 8662306a36Sopenharmony_ci action.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_L3_FORWARD; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci err = devlink_dpipe_action_put(skb, &action); 8962306a36Sopenharmony_ci if (err) 9062306a36Sopenharmony_ci return err; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci action.type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY; 9362306a36Sopenharmony_ci action.header = &mlxsw_sp_dpipe_header_metadata; 9462306a36Sopenharmony_ci action.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_L3_DROP; 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci return devlink_dpipe_action_put(skb, &action); 9762306a36Sopenharmony_ci} 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_cistatic int mlxsw_sp_dpipe_table_erif_matches_dump(void *priv, 10062306a36Sopenharmony_ci struct sk_buff *skb) 10162306a36Sopenharmony_ci{ 10262306a36Sopenharmony_ci struct devlink_dpipe_match match = {0}; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci match.type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT; 10562306a36Sopenharmony_ci match.header = &mlxsw_sp_dpipe_header_metadata; 10662306a36Sopenharmony_ci match.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci return devlink_dpipe_match_put(skb, &match); 10962306a36Sopenharmony_ci} 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_cistatic void 11262306a36Sopenharmony_cimlxsw_sp_erif_match_action_prepare(struct devlink_dpipe_match *match, 11362306a36Sopenharmony_ci struct devlink_dpipe_action *action) 11462306a36Sopenharmony_ci{ 11562306a36Sopenharmony_ci action->type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY; 11662306a36Sopenharmony_ci action->header = &mlxsw_sp_dpipe_header_metadata; 11762306a36Sopenharmony_ci action->field_id = MLXSW_SP_DPIPE_FIELD_METADATA_L3_FORWARD; 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci match->type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT; 12062306a36Sopenharmony_ci match->header = &mlxsw_sp_dpipe_header_metadata; 12162306a36Sopenharmony_ci match->field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT; 12262306a36Sopenharmony_ci} 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_cistatic int mlxsw_sp_erif_entry_prepare(struct devlink_dpipe_entry *entry, 12562306a36Sopenharmony_ci struct devlink_dpipe_value *match_value, 12662306a36Sopenharmony_ci struct devlink_dpipe_match *match, 12762306a36Sopenharmony_ci struct devlink_dpipe_value *action_value, 12862306a36Sopenharmony_ci struct devlink_dpipe_action *action) 12962306a36Sopenharmony_ci{ 13062306a36Sopenharmony_ci entry->match_values = match_value; 13162306a36Sopenharmony_ci entry->match_values_count = 1; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci entry->action_values = action_value; 13462306a36Sopenharmony_ci entry->action_values_count = 1; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci match_value->match = match; 13762306a36Sopenharmony_ci match_value->value_size = sizeof(u32); 13862306a36Sopenharmony_ci match_value->value = kmalloc(match_value->value_size, GFP_KERNEL); 13962306a36Sopenharmony_ci if (!match_value->value) 14062306a36Sopenharmony_ci return -ENOMEM; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci action_value->action = action; 14362306a36Sopenharmony_ci action_value->value_size = sizeof(u32); 14462306a36Sopenharmony_ci action_value->value = kmalloc(action_value->value_size, GFP_KERNEL); 14562306a36Sopenharmony_ci if (!action_value->value) 14662306a36Sopenharmony_ci goto err_action_alloc; 14762306a36Sopenharmony_ci return 0; 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_cierr_action_alloc: 15062306a36Sopenharmony_ci kfree(match_value->value); 15162306a36Sopenharmony_ci return -ENOMEM; 15262306a36Sopenharmony_ci} 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_cistatic int mlxsw_sp_erif_entry_get(struct mlxsw_sp *mlxsw_sp, 15562306a36Sopenharmony_ci struct devlink_dpipe_entry *entry, 15662306a36Sopenharmony_ci struct mlxsw_sp_rif *rif, 15762306a36Sopenharmony_ci bool counters_enabled) 15862306a36Sopenharmony_ci{ 15962306a36Sopenharmony_ci u32 *action_value; 16062306a36Sopenharmony_ci u32 *rif_value; 16162306a36Sopenharmony_ci u64 cnt; 16262306a36Sopenharmony_ci int err; 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci /* Set Match RIF index */ 16562306a36Sopenharmony_ci rif_value = entry->match_values->value; 16662306a36Sopenharmony_ci *rif_value = mlxsw_sp_rif_index(rif); 16762306a36Sopenharmony_ci entry->match_values->mapping_value = mlxsw_sp_rif_dev_ifindex(rif); 16862306a36Sopenharmony_ci entry->match_values->mapping_valid = true; 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci /* Set Action Forwarding */ 17162306a36Sopenharmony_ci action_value = entry->action_values->value; 17262306a36Sopenharmony_ci *action_value = 1; 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci entry->counter_valid = false; 17562306a36Sopenharmony_ci entry->counter = 0; 17662306a36Sopenharmony_ci entry->index = mlxsw_sp_rif_index(rif); 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci if (!counters_enabled) 17962306a36Sopenharmony_ci return 0; 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci err = mlxsw_sp_rif_counter_value_get(mlxsw_sp, rif, 18262306a36Sopenharmony_ci MLXSW_SP_RIF_COUNTER_EGRESS, 18362306a36Sopenharmony_ci &cnt); 18462306a36Sopenharmony_ci if (!err) { 18562306a36Sopenharmony_ci entry->counter = cnt; 18662306a36Sopenharmony_ci entry->counter_valid = true; 18762306a36Sopenharmony_ci } 18862306a36Sopenharmony_ci return 0; 18962306a36Sopenharmony_ci} 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_cistatic int 19262306a36Sopenharmony_cimlxsw_sp_dpipe_table_erif_entries_dump(void *priv, bool counters_enabled, 19362306a36Sopenharmony_ci struct devlink_dpipe_dump_ctx *dump_ctx) 19462306a36Sopenharmony_ci{ 19562306a36Sopenharmony_ci struct devlink_dpipe_value match_value, action_value; 19662306a36Sopenharmony_ci struct devlink_dpipe_action action = {0}; 19762306a36Sopenharmony_ci struct devlink_dpipe_match match = {0}; 19862306a36Sopenharmony_ci struct devlink_dpipe_entry entry = {0}; 19962306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = priv; 20062306a36Sopenharmony_ci unsigned int rif_count; 20162306a36Sopenharmony_ci int i, j; 20262306a36Sopenharmony_ci int err; 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci memset(&match_value, 0, sizeof(match_value)); 20562306a36Sopenharmony_ci memset(&action_value, 0, sizeof(action_value)); 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci mlxsw_sp_erif_match_action_prepare(&match, &action); 20862306a36Sopenharmony_ci err = mlxsw_sp_erif_entry_prepare(&entry, &match_value, &match, 20962306a36Sopenharmony_ci &action_value, &action); 21062306a36Sopenharmony_ci if (err) 21162306a36Sopenharmony_ci return err; 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci rif_count = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); 21462306a36Sopenharmony_ci mutex_lock(&mlxsw_sp->router->lock); 21562306a36Sopenharmony_ci i = 0; 21662306a36Sopenharmony_cistart_again: 21762306a36Sopenharmony_ci err = devlink_dpipe_entry_ctx_prepare(dump_ctx); 21862306a36Sopenharmony_ci if (err) 21962306a36Sopenharmony_ci goto err_ctx_prepare; 22062306a36Sopenharmony_ci j = 0; 22162306a36Sopenharmony_ci for (; i < rif_count; i++) { 22262306a36Sopenharmony_ci struct mlxsw_sp_rif *rif = mlxsw_sp_rif_by_index(mlxsw_sp, i); 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci if (!rif || !mlxsw_sp_rif_has_dev(rif)) 22562306a36Sopenharmony_ci continue; 22662306a36Sopenharmony_ci err = mlxsw_sp_erif_entry_get(mlxsw_sp, &entry, rif, 22762306a36Sopenharmony_ci counters_enabled); 22862306a36Sopenharmony_ci if (err) 22962306a36Sopenharmony_ci goto err_entry_get; 23062306a36Sopenharmony_ci err = devlink_dpipe_entry_ctx_append(dump_ctx, &entry); 23162306a36Sopenharmony_ci if (err) { 23262306a36Sopenharmony_ci if (err == -EMSGSIZE) { 23362306a36Sopenharmony_ci if (!j) 23462306a36Sopenharmony_ci goto err_entry_append; 23562306a36Sopenharmony_ci break; 23662306a36Sopenharmony_ci } 23762306a36Sopenharmony_ci goto err_entry_append; 23862306a36Sopenharmony_ci } 23962306a36Sopenharmony_ci j++; 24062306a36Sopenharmony_ci } 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci devlink_dpipe_entry_ctx_close(dump_ctx); 24362306a36Sopenharmony_ci if (i != rif_count) 24462306a36Sopenharmony_ci goto start_again; 24562306a36Sopenharmony_ci mutex_unlock(&mlxsw_sp->router->lock); 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci devlink_dpipe_entry_clear(&entry); 24862306a36Sopenharmony_ci return 0; 24962306a36Sopenharmony_cierr_entry_append: 25062306a36Sopenharmony_cierr_entry_get: 25162306a36Sopenharmony_cierr_ctx_prepare: 25262306a36Sopenharmony_ci mutex_unlock(&mlxsw_sp->router->lock); 25362306a36Sopenharmony_ci devlink_dpipe_entry_clear(&entry); 25462306a36Sopenharmony_ci return err; 25562306a36Sopenharmony_ci} 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_cistatic int mlxsw_sp_dpipe_table_erif_counters_update(void *priv, bool enable) 25862306a36Sopenharmony_ci{ 25962306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = priv; 26062306a36Sopenharmony_ci int i; 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci mutex_lock(&mlxsw_sp->router->lock); 26362306a36Sopenharmony_ci for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++) { 26462306a36Sopenharmony_ci struct mlxsw_sp_rif *rif = mlxsw_sp_rif_by_index(mlxsw_sp, i); 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci if (!rif) 26762306a36Sopenharmony_ci continue; 26862306a36Sopenharmony_ci if (enable) 26962306a36Sopenharmony_ci mlxsw_sp_rif_counter_alloc(rif, 27062306a36Sopenharmony_ci MLXSW_SP_RIF_COUNTER_EGRESS); 27162306a36Sopenharmony_ci else 27262306a36Sopenharmony_ci mlxsw_sp_rif_counter_free(rif, 27362306a36Sopenharmony_ci MLXSW_SP_RIF_COUNTER_EGRESS); 27462306a36Sopenharmony_ci } 27562306a36Sopenharmony_ci mutex_unlock(&mlxsw_sp->router->lock); 27662306a36Sopenharmony_ci return 0; 27762306a36Sopenharmony_ci} 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_cistatic u64 mlxsw_sp_dpipe_table_erif_size_get(void *priv) 28062306a36Sopenharmony_ci{ 28162306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = priv; 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci return MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); 28462306a36Sopenharmony_ci} 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_cistatic struct devlink_dpipe_table_ops mlxsw_sp_erif_ops = { 28762306a36Sopenharmony_ci .matches_dump = mlxsw_sp_dpipe_table_erif_matches_dump, 28862306a36Sopenharmony_ci .actions_dump = mlxsw_sp_dpipe_table_erif_actions_dump, 28962306a36Sopenharmony_ci .entries_dump = mlxsw_sp_dpipe_table_erif_entries_dump, 29062306a36Sopenharmony_ci .counters_set_update = mlxsw_sp_dpipe_table_erif_counters_update, 29162306a36Sopenharmony_ci .size_get = mlxsw_sp_dpipe_table_erif_size_get, 29262306a36Sopenharmony_ci}; 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_cistatic int mlxsw_sp_dpipe_erif_table_init(struct mlxsw_sp *mlxsw_sp) 29562306a36Sopenharmony_ci{ 29662306a36Sopenharmony_ci struct devlink *devlink = priv_to_devlink(mlxsw_sp->core); 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci return devl_dpipe_table_register(devlink, 29962306a36Sopenharmony_ci MLXSW_SP_DPIPE_TABLE_NAME_ERIF, 30062306a36Sopenharmony_ci &mlxsw_sp_erif_ops, 30162306a36Sopenharmony_ci mlxsw_sp, false); 30262306a36Sopenharmony_ci} 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_cistatic void mlxsw_sp_dpipe_erif_table_fini(struct mlxsw_sp *mlxsw_sp) 30562306a36Sopenharmony_ci{ 30662306a36Sopenharmony_ci struct devlink *devlink = priv_to_devlink(mlxsw_sp->core); 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci devl_dpipe_table_unregister(devlink, MLXSW_SP_DPIPE_TABLE_NAME_ERIF); 30962306a36Sopenharmony_ci} 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_cistatic int mlxsw_sp_dpipe_table_host_matches_dump(struct sk_buff *skb, int type) 31262306a36Sopenharmony_ci{ 31362306a36Sopenharmony_ci struct devlink_dpipe_match match = {0}; 31462306a36Sopenharmony_ci int err; 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci match.type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT; 31762306a36Sopenharmony_ci match.header = &mlxsw_sp_dpipe_header_metadata; 31862306a36Sopenharmony_ci match.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT; 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci err = devlink_dpipe_match_put(skb, &match); 32162306a36Sopenharmony_ci if (err) 32262306a36Sopenharmony_ci return err; 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci switch (type) { 32562306a36Sopenharmony_ci case AF_INET: 32662306a36Sopenharmony_ci match.type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT; 32762306a36Sopenharmony_ci match.header = &devlink_dpipe_header_ipv4; 32862306a36Sopenharmony_ci match.field_id = DEVLINK_DPIPE_FIELD_IPV4_DST_IP; 32962306a36Sopenharmony_ci break; 33062306a36Sopenharmony_ci case AF_INET6: 33162306a36Sopenharmony_ci match.type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT; 33262306a36Sopenharmony_ci match.header = &devlink_dpipe_header_ipv6; 33362306a36Sopenharmony_ci match.field_id = DEVLINK_DPIPE_FIELD_IPV6_DST_IP; 33462306a36Sopenharmony_ci break; 33562306a36Sopenharmony_ci default: 33662306a36Sopenharmony_ci WARN_ON(1); 33762306a36Sopenharmony_ci return -EINVAL; 33862306a36Sopenharmony_ci } 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci return devlink_dpipe_match_put(skb, &match); 34162306a36Sopenharmony_ci} 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_cistatic int 34462306a36Sopenharmony_cimlxsw_sp_dpipe_table_host4_matches_dump(void *priv, struct sk_buff *skb) 34562306a36Sopenharmony_ci{ 34662306a36Sopenharmony_ci return mlxsw_sp_dpipe_table_host_matches_dump(skb, AF_INET); 34762306a36Sopenharmony_ci} 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_cistatic int 35062306a36Sopenharmony_cimlxsw_sp_dpipe_table_host_actions_dump(void *priv, struct sk_buff *skb) 35162306a36Sopenharmony_ci{ 35262306a36Sopenharmony_ci struct devlink_dpipe_action action = {0}; 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci action.type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY; 35562306a36Sopenharmony_ci action.header = &devlink_dpipe_header_ethernet; 35662306a36Sopenharmony_ci action.field_id = DEVLINK_DPIPE_FIELD_ETHERNET_DST_MAC; 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci return devlink_dpipe_action_put(skb, &action); 35962306a36Sopenharmony_ci} 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_cienum mlxsw_sp_dpipe_table_host_match { 36262306a36Sopenharmony_ci MLXSW_SP_DPIPE_TABLE_HOST_MATCH_RIF, 36362306a36Sopenharmony_ci MLXSW_SP_DPIPE_TABLE_HOST_MATCH_DIP, 36462306a36Sopenharmony_ci MLXSW_SP_DPIPE_TABLE_HOST_MATCH_COUNT, 36562306a36Sopenharmony_ci}; 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_cistatic void 36862306a36Sopenharmony_cimlxsw_sp_dpipe_table_host_match_action_prepare(struct devlink_dpipe_match *matches, 36962306a36Sopenharmony_ci struct devlink_dpipe_action *action, 37062306a36Sopenharmony_ci int type) 37162306a36Sopenharmony_ci{ 37262306a36Sopenharmony_ci struct devlink_dpipe_match *match; 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci match = &matches[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_RIF]; 37562306a36Sopenharmony_ci match->type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT; 37662306a36Sopenharmony_ci match->header = &mlxsw_sp_dpipe_header_metadata; 37762306a36Sopenharmony_ci match->field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT; 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci match = &matches[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_DIP]; 38062306a36Sopenharmony_ci match->type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT; 38162306a36Sopenharmony_ci switch (type) { 38262306a36Sopenharmony_ci case AF_INET: 38362306a36Sopenharmony_ci match->header = &devlink_dpipe_header_ipv4; 38462306a36Sopenharmony_ci match->field_id = DEVLINK_DPIPE_FIELD_IPV4_DST_IP; 38562306a36Sopenharmony_ci break; 38662306a36Sopenharmony_ci case AF_INET6: 38762306a36Sopenharmony_ci match->header = &devlink_dpipe_header_ipv6; 38862306a36Sopenharmony_ci match->field_id = DEVLINK_DPIPE_FIELD_IPV6_DST_IP; 38962306a36Sopenharmony_ci break; 39062306a36Sopenharmony_ci default: 39162306a36Sopenharmony_ci WARN_ON(1); 39262306a36Sopenharmony_ci return; 39362306a36Sopenharmony_ci } 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci action->type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY; 39662306a36Sopenharmony_ci action->header = &devlink_dpipe_header_ethernet; 39762306a36Sopenharmony_ci action->field_id = DEVLINK_DPIPE_FIELD_ETHERNET_DST_MAC; 39862306a36Sopenharmony_ci} 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_cistatic int 40162306a36Sopenharmony_cimlxsw_sp_dpipe_table_host_entry_prepare(struct devlink_dpipe_entry *entry, 40262306a36Sopenharmony_ci struct devlink_dpipe_value *match_values, 40362306a36Sopenharmony_ci struct devlink_dpipe_match *matches, 40462306a36Sopenharmony_ci struct devlink_dpipe_value *action_value, 40562306a36Sopenharmony_ci struct devlink_dpipe_action *action, 40662306a36Sopenharmony_ci int type) 40762306a36Sopenharmony_ci{ 40862306a36Sopenharmony_ci struct devlink_dpipe_value *match_value; 40962306a36Sopenharmony_ci struct devlink_dpipe_match *match; 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci entry->match_values = match_values; 41262306a36Sopenharmony_ci entry->match_values_count = MLXSW_SP_DPIPE_TABLE_HOST_MATCH_COUNT; 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci entry->action_values = action_value; 41562306a36Sopenharmony_ci entry->action_values_count = 1; 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci match = &matches[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_RIF]; 41862306a36Sopenharmony_ci match_value = &match_values[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_RIF]; 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci match_value->match = match; 42162306a36Sopenharmony_ci match_value->value_size = sizeof(u32); 42262306a36Sopenharmony_ci match_value->value = kmalloc(match_value->value_size, GFP_KERNEL); 42362306a36Sopenharmony_ci if (!match_value->value) 42462306a36Sopenharmony_ci return -ENOMEM; 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci match = &matches[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_DIP]; 42762306a36Sopenharmony_ci match_value = &match_values[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_DIP]; 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci match_value->match = match; 43062306a36Sopenharmony_ci switch (type) { 43162306a36Sopenharmony_ci case AF_INET: 43262306a36Sopenharmony_ci match_value->value_size = sizeof(u32); 43362306a36Sopenharmony_ci break; 43462306a36Sopenharmony_ci case AF_INET6: 43562306a36Sopenharmony_ci match_value->value_size = sizeof(struct in6_addr); 43662306a36Sopenharmony_ci break; 43762306a36Sopenharmony_ci default: 43862306a36Sopenharmony_ci WARN_ON(1); 43962306a36Sopenharmony_ci return -EINVAL; 44062306a36Sopenharmony_ci } 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci match_value->value = kmalloc(match_value->value_size, GFP_KERNEL); 44362306a36Sopenharmony_ci if (!match_value->value) 44462306a36Sopenharmony_ci return -ENOMEM; 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci action_value->action = action; 44762306a36Sopenharmony_ci action_value->value_size = sizeof(u64); 44862306a36Sopenharmony_ci action_value->value = kmalloc(action_value->value_size, GFP_KERNEL); 44962306a36Sopenharmony_ci if (!action_value->value) 45062306a36Sopenharmony_ci return -ENOMEM; 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci return 0; 45362306a36Sopenharmony_ci} 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_cistatic void 45662306a36Sopenharmony_ci__mlxsw_sp_dpipe_table_host_entry_fill(struct devlink_dpipe_entry *entry, 45762306a36Sopenharmony_ci struct mlxsw_sp_rif *rif, 45862306a36Sopenharmony_ci unsigned char *ha, void *dip) 45962306a36Sopenharmony_ci{ 46062306a36Sopenharmony_ci struct devlink_dpipe_value *value; 46162306a36Sopenharmony_ci u32 *rif_value; 46262306a36Sopenharmony_ci u8 *ha_value; 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci /* Set Match RIF index */ 46562306a36Sopenharmony_ci value = &entry->match_values[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_RIF]; 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci rif_value = value->value; 46862306a36Sopenharmony_ci *rif_value = mlxsw_sp_rif_index(rif); 46962306a36Sopenharmony_ci value->mapping_value = mlxsw_sp_rif_dev_ifindex(rif); 47062306a36Sopenharmony_ci value->mapping_valid = true; 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci /* Set Match DIP */ 47362306a36Sopenharmony_ci value = &entry->match_values[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_DIP]; 47462306a36Sopenharmony_ci memcpy(value->value, dip, value->value_size); 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci /* Set Action DMAC */ 47762306a36Sopenharmony_ci value = entry->action_values; 47862306a36Sopenharmony_ci ha_value = value->value; 47962306a36Sopenharmony_ci ether_addr_copy(ha_value, ha); 48062306a36Sopenharmony_ci} 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_cistatic void 48362306a36Sopenharmony_cimlxsw_sp_dpipe_table_host4_entry_fill(struct devlink_dpipe_entry *entry, 48462306a36Sopenharmony_ci struct mlxsw_sp_neigh_entry *neigh_entry, 48562306a36Sopenharmony_ci struct mlxsw_sp_rif *rif) 48662306a36Sopenharmony_ci{ 48762306a36Sopenharmony_ci unsigned char *ha; 48862306a36Sopenharmony_ci u32 dip; 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci ha = mlxsw_sp_neigh_entry_ha(neigh_entry); 49162306a36Sopenharmony_ci dip = mlxsw_sp_neigh4_entry_dip(neigh_entry); 49262306a36Sopenharmony_ci __mlxsw_sp_dpipe_table_host_entry_fill(entry, rif, ha, &dip); 49362306a36Sopenharmony_ci} 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_cistatic void 49662306a36Sopenharmony_cimlxsw_sp_dpipe_table_host6_entry_fill(struct devlink_dpipe_entry *entry, 49762306a36Sopenharmony_ci struct mlxsw_sp_neigh_entry *neigh_entry, 49862306a36Sopenharmony_ci struct mlxsw_sp_rif *rif) 49962306a36Sopenharmony_ci{ 50062306a36Sopenharmony_ci struct in6_addr *dip; 50162306a36Sopenharmony_ci unsigned char *ha; 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci ha = mlxsw_sp_neigh_entry_ha(neigh_entry); 50462306a36Sopenharmony_ci dip = mlxsw_sp_neigh6_entry_dip(neigh_entry); 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci __mlxsw_sp_dpipe_table_host_entry_fill(entry, rif, ha, dip); 50762306a36Sopenharmony_ci} 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_cistatic void 51062306a36Sopenharmony_cimlxsw_sp_dpipe_table_host_entry_fill(struct mlxsw_sp *mlxsw_sp, 51162306a36Sopenharmony_ci struct devlink_dpipe_entry *entry, 51262306a36Sopenharmony_ci struct mlxsw_sp_neigh_entry *neigh_entry, 51362306a36Sopenharmony_ci struct mlxsw_sp_rif *rif, 51462306a36Sopenharmony_ci int type) 51562306a36Sopenharmony_ci{ 51662306a36Sopenharmony_ci int err; 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci switch (type) { 51962306a36Sopenharmony_ci case AF_INET: 52062306a36Sopenharmony_ci mlxsw_sp_dpipe_table_host4_entry_fill(entry, neigh_entry, rif); 52162306a36Sopenharmony_ci break; 52262306a36Sopenharmony_ci case AF_INET6: 52362306a36Sopenharmony_ci mlxsw_sp_dpipe_table_host6_entry_fill(entry, neigh_entry, rif); 52462306a36Sopenharmony_ci break; 52562306a36Sopenharmony_ci default: 52662306a36Sopenharmony_ci WARN_ON(1); 52762306a36Sopenharmony_ci return; 52862306a36Sopenharmony_ci } 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci err = mlxsw_sp_neigh_counter_get(mlxsw_sp, neigh_entry, 53162306a36Sopenharmony_ci &entry->counter); 53262306a36Sopenharmony_ci if (!err) 53362306a36Sopenharmony_ci entry->counter_valid = true; 53462306a36Sopenharmony_ci} 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_cistatic int 53762306a36Sopenharmony_cimlxsw_sp_dpipe_table_host_entries_get(struct mlxsw_sp *mlxsw_sp, 53862306a36Sopenharmony_ci struct devlink_dpipe_entry *entry, 53962306a36Sopenharmony_ci bool counters_enabled, 54062306a36Sopenharmony_ci struct devlink_dpipe_dump_ctx *dump_ctx, 54162306a36Sopenharmony_ci int type) 54262306a36Sopenharmony_ci{ 54362306a36Sopenharmony_ci int rif_neigh_count = 0; 54462306a36Sopenharmony_ci int rif_neigh_skip = 0; 54562306a36Sopenharmony_ci int neigh_count = 0; 54662306a36Sopenharmony_ci int rif_count; 54762306a36Sopenharmony_ci int i, j; 54862306a36Sopenharmony_ci int err; 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci mutex_lock(&mlxsw_sp->router->lock); 55162306a36Sopenharmony_ci i = 0; 55262306a36Sopenharmony_ci rif_count = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); 55362306a36Sopenharmony_cistart_again: 55462306a36Sopenharmony_ci err = devlink_dpipe_entry_ctx_prepare(dump_ctx); 55562306a36Sopenharmony_ci if (err) 55662306a36Sopenharmony_ci goto err_ctx_prepare; 55762306a36Sopenharmony_ci j = 0; 55862306a36Sopenharmony_ci rif_neigh_skip = rif_neigh_count; 55962306a36Sopenharmony_ci for (; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++) { 56062306a36Sopenharmony_ci struct mlxsw_sp_rif *rif = mlxsw_sp_rif_by_index(mlxsw_sp, i); 56162306a36Sopenharmony_ci struct mlxsw_sp_neigh_entry *neigh_entry; 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci if (!rif) 56462306a36Sopenharmony_ci continue; 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci rif_neigh_count = 0; 56762306a36Sopenharmony_ci mlxsw_sp_rif_neigh_for_each(neigh_entry, rif) { 56862306a36Sopenharmony_ci int neigh_type = mlxsw_sp_neigh_entry_type(neigh_entry); 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci if (neigh_type != type) 57162306a36Sopenharmony_ci continue; 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci if (neigh_type == AF_INET6 && 57462306a36Sopenharmony_ci mlxsw_sp_neigh_ipv6_ignore(neigh_entry)) 57562306a36Sopenharmony_ci continue; 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci if (rif_neigh_count < rif_neigh_skip) 57862306a36Sopenharmony_ci goto skip; 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci mlxsw_sp_dpipe_table_host_entry_fill(mlxsw_sp, entry, 58162306a36Sopenharmony_ci neigh_entry, rif, 58262306a36Sopenharmony_ci type); 58362306a36Sopenharmony_ci entry->index = neigh_count; 58462306a36Sopenharmony_ci err = devlink_dpipe_entry_ctx_append(dump_ctx, entry); 58562306a36Sopenharmony_ci if (err) { 58662306a36Sopenharmony_ci if (err == -EMSGSIZE) { 58762306a36Sopenharmony_ci if (!j) 58862306a36Sopenharmony_ci goto err_entry_append; 58962306a36Sopenharmony_ci else 59062306a36Sopenharmony_ci goto out; 59162306a36Sopenharmony_ci } 59262306a36Sopenharmony_ci goto err_entry_append; 59362306a36Sopenharmony_ci } 59462306a36Sopenharmony_ci neigh_count++; 59562306a36Sopenharmony_ci j++; 59662306a36Sopenharmony_ciskip: 59762306a36Sopenharmony_ci rif_neigh_count++; 59862306a36Sopenharmony_ci } 59962306a36Sopenharmony_ci rif_neigh_skip = 0; 60062306a36Sopenharmony_ci } 60162306a36Sopenharmony_ciout: 60262306a36Sopenharmony_ci devlink_dpipe_entry_ctx_close(dump_ctx); 60362306a36Sopenharmony_ci if (i != rif_count) 60462306a36Sopenharmony_ci goto start_again; 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci mutex_unlock(&mlxsw_sp->router->lock); 60762306a36Sopenharmony_ci return 0; 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_cierr_ctx_prepare: 61062306a36Sopenharmony_cierr_entry_append: 61162306a36Sopenharmony_ci mutex_unlock(&mlxsw_sp->router->lock); 61262306a36Sopenharmony_ci return err; 61362306a36Sopenharmony_ci} 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_cistatic int 61662306a36Sopenharmony_cimlxsw_sp_dpipe_table_host_entries_dump(struct mlxsw_sp *mlxsw_sp, 61762306a36Sopenharmony_ci bool counters_enabled, 61862306a36Sopenharmony_ci struct devlink_dpipe_dump_ctx *dump_ctx, 61962306a36Sopenharmony_ci int type) 62062306a36Sopenharmony_ci{ 62162306a36Sopenharmony_ci struct devlink_dpipe_value match_values[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_COUNT]; 62262306a36Sopenharmony_ci struct devlink_dpipe_match matches[MLXSW_SP_DPIPE_TABLE_HOST_MATCH_COUNT]; 62362306a36Sopenharmony_ci struct devlink_dpipe_value action_value; 62462306a36Sopenharmony_ci struct devlink_dpipe_action action = {0}; 62562306a36Sopenharmony_ci struct devlink_dpipe_entry entry = {0}; 62662306a36Sopenharmony_ci int err; 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci memset(matches, 0, MLXSW_SP_DPIPE_TABLE_HOST_MATCH_COUNT * 62962306a36Sopenharmony_ci sizeof(matches[0])); 63062306a36Sopenharmony_ci memset(match_values, 0, MLXSW_SP_DPIPE_TABLE_HOST_MATCH_COUNT * 63162306a36Sopenharmony_ci sizeof(match_values[0])); 63262306a36Sopenharmony_ci memset(&action_value, 0, sizeof(action_value)); 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci mlxsw_sp_dpipe_table_host_match_action_prepare(matches, &action, type); 63562306a36Sopenharmony_ci err = mlxsw_sp_dpipe_table_host_entry_prepare(&entry, match_values, 63662306a36Sopenharmony_ci matches, &action_value, 63762306a36Sopenharmony_ci &action, type); 63862306a36Sopenharmony_ci if (err) 63962306a36Sopenharmony_ci goto out; 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci err = mlxsw_sp_dpipe_table_host_entries_get(mlxsw_sp, &entry, 64262306a36Sopenharmony_ci counters_enabled, dump_ctx, 64362306a36Sopenharmony_ci type); 64462306a36Sopenharmony_ciout: 64562306a36Sopenharmony_ci devlink_dpipe_entry_clear(&entry); 64662306a36Sopenharmony_ci return err; 64762306a36Sopenharmony_ci} 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_cistatic int 65062306a36Sopenharmony_cimlxsw_sp_dpipe_table_host4_entries_dump(void *priv, bool counters_enabled, 65162306a36Sopenharmony_ci struct devlink_dpipe_dump_ctx *dump_ctx) 65262306a36Sopenharmony_ci{ 65362306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = priv; 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci return mlxsw_sp_dpipe_table_host_entries_dump(mlxsw_sp, 65662306a36Sopenharmony_ci counters_enabled, 65762306a36Sopenharmony_ci dump_ctx, AF_INET); 65862306a36Sopenharmony_ci} 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_cistatic void 66162306a36Sopenharmony_cimlxsw_sp_dpipe_table_host_counters_update(struct mlxsw_sp *mlxsw_sp, 66262306a36Sopenharmony_ci bool enable, int type) 66362306a36Sopenharmony_ci{ 66462306a36Sopenharmony_ci int i; 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci mutex_lock(&mlxsw_sp->router->lock); 66762306a36Sopenharmony_ci for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++) { 66862306a36Sopenharmony_ci struct mlxsw_sp_rif *rif = mlxsw_sp_rif_by_index(mlxsw_sp, i); 66962306a36Sopenharmony_ci struct mlxsw_sp_neigh_entry *neigh_entry; 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci if (!rif) 67262306a36Sopenharmony_ci continue; 67362306a36Sopenharmony_ci mlxsw_sp_rif_neigh_for_each(neigh_entry, rif) { 67462306a36Sopenharmony_ci int neigh_type = mlxsw_sp_neigh_entry_type(neigh_entry); 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci if (neigh_type != type) 67762306a36Sopenharmony_ci continue; 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci if (neigh_type == AF_INET6 && 68062306a36Sopenharmony_ci mlxsw_sp_neigh_ipv6_ignore(neigh_entry)) 68162306a36Sopenharmony_ci continue; 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci mlxsw_sp_neigh_entry_counter_update(mlxsw_sp, 68462306a36Sopenharmony_ci neigh_entry, 68562306a36Sopenharmony_ci enable); 68662306a36Sopenharmony_ci } 68762306a36Sopenharmony_ci } 68862306a36Sopenharmony_ci mutex_unlock(&mlxsw_sp->router->lock); 68962306a36Sopenharmony_ci} 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_cistatic int mlxsw_sp_dpipe_table_host4_counters_update(void *priv, bool enable) 69262306a36Sopenharmony_ci{ 69362306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = priv; 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ci mlxsw_sp_dpipe_table_host_counters_update(mlxsw_sp, enable, AF_INET); 69662306a36Sopenharmony_ci return 0; 69762306a36Sopenharmony_ci} 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_cistatic u64 70062306a36Sopenharmony_cimlxsw_sp_dpipe_table_host_size_get(struct mlxsw_sp *mlxsw_sp, int type) 70162306a36Sopenharmony_ci{ 70262306a36Sopenharmony_ci u64 size = 0; 70362306a36Sopenharmony_ci int i; 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_ci mutex_lock(&mlxsw_sp->router->lock); 70662306a36Sopenharmony_ci for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++) { 70762306a36Sopenharmony_ci struct mlxsw_sp_rif *rif = mlxsw_sp_rif_by_index(mlxsw_sp, i); 70862306a36Sopenharmony_ci struct mlxsw_sp_neigh_entry *neigh_entry; 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci if (!rif) 71162306a36Sopenharmony_ci continue; 71262306a36Sopenharmony_ci mlxsw_sp_rif_neigh_for_each(neigh_entry, rif) { 71362306a36Sopenharmony_ci int neigh_type = mlxsw_sp_neigh_entry_type(neigh_entry); 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_ci if (neigh_type != type) 71662306a36Sopenharmony_ci continue; 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci if (neigh_type == AF_INET6 && 71962306a36Sopenharmony_ci mlxsw_sp_neigh_ipv6_ignore(neigh_entry)) 72062306a36Sopenharmony_ci continue; 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci size++; 72362306a36Sopenharmony_ci } 72462306a36Sopenharmony_ci } 72562306a36Sopenharmony_ci mutex_unlock(&mlxsw_sp->router->lock); 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci return size; 72862306a36Sopenharmony_ci} 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_cistatic u64 mlxsw_sp_dpipe_table_host4_size_get(void *priv) 73162306a36Sopenharmony_ci{ 73262306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = priv; 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_ci return mlxsw_sp_dpipe_table_host_size_get(mlxsw_sp, AF_INET); 73562306a36Sopenharmony_ci} 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_cistatic struct devlink_dpipe_table_ops mlxsw_sp_host4_ops = { 73862306a36Sopenharmony_ci .matches_dump = mlxsw_sp_dpipe_table_host4_matches_dump, 73962306a36Sopenharmony_ci .actions_dump = mlxsw_sp_dpipe_table_host_actions_dump, 74062306a36Sopenharmony_ci .entries_dump = mlxsw_sp_dpipe_table_host4_entries_dump, 74162306a36Sopenharmony_ci .counters_set_update = mlxsw_sp_dpipe_table_host4_counters_update, 74262306a36Sopenharmony_ci .size_get = mlxsw_sp_dpipe_table_host4_size_get, 74362306a36Sopenharmony_ci}; 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_ci#define MLXSW_SP_DPIPE_TABLE_RESOURCE_UNIT_HOST4 1 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_cistatic int mlxsw_sp_dpipe_host4_table_init(struct mlxsw_sp *mlxsw_sp) 74862306a36Sopenharmony_ci{ 74962306a36Sopenharmony_ci struct devlink *devlink = priv_to_devlink(mlxsw_sp->core); 75062306a36Sopenharmony_ci int err; 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_ci err = devl_dpipe_table_register(devlink, 75362306a36Sopenharmony_ci MLXSW_SP_DPIPE_TABLE_NAME_HOST4, 75462306a36Sopenharmony_ci &mlxsw_sp_host4_ops, 75562306a36Sopenharmony_ci mlxsw_sp, false); 75662306a36Sopenharmony_ci if (err) 75762306a36Sopenharmony_ci return err; 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_ci err = devl_dpipe_table_resource_set(devlink, 76062306a36Sopenharmony_ci MLXSW_SP_DPIPE_TABLE_NAME_HOST4, 76162306a36Sopenharmony_ci MLXSW_SP_RESOURCE_KVD_HASH_SINGLE, 76262306a36Sopenharmony_ci MLXSW_SP_DPIPE_TABLE_RESOURCE_UNIT_HOST4); 76362306a36Sopenharmony_ci if (err) 76462306a36Sopenharmony_ci goto err_resource_set; 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_ci return 0; 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_cierr_resource_set: 76962306a36Sopenharmony_ci devl_dpipe_table_unregister(devlink, 77062306a36Sopenharmony_ci MLXSW_SP_DPIPE_TABLE_NAME_HOST4); 77162306a36Sopenharmony_ci return err; 77262306a36Sopenharmony_ci} 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_cistatic void mlxsw_sp_dpipe_host4_table_fini(struct mlxsw_sp *mlxsw_sp) 77562306a36Sopenharmony_ci{ 77662306a36Sopenharmony_ci struct devlink *devlink = priv_to_devlink(mlxsw_sp->core); 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ci devl_dpipe_table_unregister(devlink, 77962306a36Sopenharmony_ci MLXSW_SP_DPIPE_TABLE_NAME_HOST4); 78062306a36Sopenharmony_ci} 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_cistatic int 78362306a36Sopenharmony_cimlxsw_sp_dpipe_table_host6_matches_dump(void *priv, struct sk_buff *skb) 78462306a36Sopenharmony_ci{ 78562306a36Sopenharmony_ci return mlxsw_sp_dpipe_table_host_matches_dump(skb, AF_INET6); 78662306a36Sopenharmony_ci} 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_cistatic int 78962306a36Sopenharmony_cimlxsw_sp_dpipe_table_host6_entries_dump(void *priv, bool counters_enabled, 79062306a36Sopenharmony_ci struct devlink_dpipe_dump_ctx *dump_ctx) 79162306a36Sopenharmony_ci{ 79262306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = priv; 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_ci return mlxsw_sp_dpipe_table_host_entries_dump(mlxsw_sp, 79562306a36Sopenharmony_ci counters_enabled, 79662306a36Sopenharmony_ci dump_ctx, AF_INET6); 79762306a36Sopenharmony_ci} 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_cistatic int mlxsw_sp_dpipe_table_host6_counters_update(void *priv, bool enable) 80062306a36Sopenharmony_ci{ 80162306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = priv; 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_ci mlxsw_sp_dpipe_table_host_counters_update(mlxsw_sp, enable, AF_INET6); 80462306a36Sopenharmony_ci return 0; 80562306a36Sopenharmony_ci} 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_cistatic u64 mlxsw_sp_dpipe_table_host6_size_get(void *priv) 80862306a36Sopenharmony_ci{ 80962306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = priv; 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci return mlxsw_sp_dpipe_table_host_size_get(mlxsw_sp, AF_INET6); 81262306a36Sopenharmony_ci} 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_cistatic struct devlink_dpipe_table_ops mlxsw_sp_host6_ops = { 81562306a36Sopenharmony_ci .matches_dump = mlxsw_sp_dpipe_table_host6_matches_dump, 81662306a36Sopenharmony_ci .actions_dump = mlxsw_sp_dpipe_table_host_actions_dump, 81762306a36Sopenharmony_ci .entries_dump = mlxsw_sp_dpipe_table_host6_entries_dump, 81862306a36Sopenharmony_ci .counters_set_update = mlxsw_sp_dpipe_table_host6_counters_update, 81962306a36Sopenharmony_ci .size_get = mlxsw_sp_dpipe_table_host6_size_get, 82062306a36Sopenharmony_ci}; 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_ci#define MLXSW_SP_DPIPE_TABLE_RESOURCE_UNIT_HOST6 2 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_cistatic int mlxsw_sp_dpipe_host6_table_init(struct mlxsw_sp *mlxsw_sp) 82562306a36Sopenharmony_ci{ 82662306a36Sopenharmony_ci struct devlink *devlink = priv_to_devlink(mlxsw_sp->core); 82762306a36Sopenharmony_ci int err; 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_ci err = devl_dpipe_table_register(devlink, 83062306a36Sopenharmony_ci MLXSW_SP_DPIPE_TABLE_NAME_HOST6, 83162306a36Sopenharmony_ci &mlxsw_sp_host6_ops, 83262306a36Sopenharmony_ci mlxsw_sp, false); 83362306a36Sopenharmony_ci if (err) 83462306a36Sopenharmony_ci return err; 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_ci err = devl_dpipe_table_resource_set(devlink, 83762306a36Sopenharmony_ci MLXSW_SP_DPIPE_TABLE_NAME_HOST6, 83862306a36Sopenharmony_ci MLXSW_SP_RESOURCE_KVD_HASH_DOUBLE, 83962306a36Sopenharmony_ci MLXSW_SP_DPIPE_TABLE_RESOURCE_UNIT_HOST6); 84062306a36Sopenharmony_ci if (err) 84162306a36Sopenharmony_ci goto err_resource_set; 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_ci return 0; 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_cierr_resource_set: 84662306a36Sopenharmony_ci devl_dpipe_table_unregister(devlink, 84762306a36Sopenharmony_ci MLXSW_SP_DPIPE_TABLE_NAME_HOST6); 84862306a36Sopenharmony_ci return err; 84962306a36Sopenharmony_ci} 85062306a36Sopenharmony_ci 85162306a36Sopenharmony_cistatic void mlxsw_sp_dpipe_host6_table_fini(struct mlxsw_sp *mlxsw_sp) 85262306a36Sopenharmony_ci{ 85362306a36Sopenharmony_ci struct devlink *devlink = priv_to_devlink(mlxsw_sp->core); 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_ci devl_dpipe_table_unregister(devlink, 85662306a36Sopenharmony_ci MLXSW_SP_DPIPE_TABLE_NAME_HOST6); 85762306a36Sopenharmony_ci} 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_cistatic int mlxsw_sp_dpipe_table_adj_matches_dump(void *priv, 86062306a36Sopenharmony_ci struct sk_buff *skb) 86162306a36Sopenharmony_ci{ 86262306a36Sopenharmony_ci struct devlink_dpipe_match match = {0}; 86362306a36Sopenharmony_ci int err; 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_ci match.type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT; 86662306a36Sopenharmony_ci match.header = &mlxsw_sp_dpipe_header_metadata; 86762306a36Sopenharmony_ci match.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_INDEX; 86862306a36Sopenharmony_ci 86962306a36Sopenharmony_ci err = devlink_dpipe_match_put(skb, &match); 87062306a36Sopenharmony_ci if (err) 87162306a36Sopenharmony_ci return err; 87262306a36Sopenharmony_ci 87362306a36Sopenharmony_ci match.type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT; 87462306a36Sopenharmony_ci match.header = &mlxsw_sp_dpipe_header_metadata; 87562306a36Sopenharmony_ci match.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_SIZE; 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_ci err = devlink_dpipe_match_put(skb, &match); 87862306a36Sopenharmony_ci if (err) 87962306a36Sopenharmony_ci return err; 88062306a36Sopenharmony_ci 88162306a36Sopenharmony_ci match.type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT; 88262306a36Sopenharmony_ci match.header = &mlxsw_sp_dpipe_header_metadata; 88362306a36Sopenharmony_ci match.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_HASH_INDEX; 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_ci return devlink_dpipe_match_put(skb, &match); 88662306a36Sopenharmony_ci} 88762306a36Sopenharmony_ci 88862306a36Sopenharmony_cistatic int mlxsw_sp_dpipe_table_adj_actions_dump(void *priv, 88962306a36Sopenharmony_ci struct sk_buff *skb) 89062306a36Sopenharmony_ci{ 89162306a36Sopenharmony_ci struct devlink_dpipe_action action = {0}; 89262306a36Sopenharmony_ci int err; 89362306a36Sopenharmony_ci 89462306a36Sopenharmony_ci action.type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY; 89562306a36Sopenharmony_ci action.header = &devlink_dpipe_header_ethernet; 89662306a36Sopenharmony_ci action.field_id = DEVLINK_DPIPE_FIELD_ETHERNET_DST_MAC; 89762306a36Sopenharmony_ci 89862306a36Sopenharmony_ci err = devlink_dpipe_action_put(skb, &action); 89962306a36Sopenharmony_ci if (err) 90062306a36Sopenharmony_ci return err; 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_ci action.type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY; 90362306a36Sopenharmony_ci action.header = &mlxsw_sp_dpipe_header_metadata; 90462306a36Sopenharmony_ci action.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT; 90562306a36Sopenharmony_ci 90662306a36Sopenharmony_ci return devlink_dpipe_action_put(skb, &action); 90762306a36Sopenharmony_ci} 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_cistatic u64 mlxsw_sp_dpipe_table_adj_size(struct mlxsw_sp *mlxsw_sp) 91062306a36Sopenharmony_ci{ 91162306a36Sopenharmony_ci struct mlxsw_sp_nexthop *nh; 91262306a36Sopenharmony_ci u64 size = 0; 91362306a36Sopenharmony_ci 91462306a36Sopenharmony_ci mlxsw_sp_nexthop_for_each(nh, mlxsw_sp->router) 91562306a36Sopenharmony_ci if (mlxsw_sp_nexthop_is_forward(nh) && 91662306a36Sopenharmony_ci !mlxsw_sp_nexthop_group_has_ipip(nh)) 91762306a36Sopenharmony_ci size++; 91862306a36Sopenharmony_ci return size; 91962306a36Sopenharmony_ci} 92062306a36Sopenharmony_ci 92162306a36Sopenharmony_cienum mlxsw_sp_dpipe_table_adj_match { 92262306a36Sopenharmony_ci MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_INDEX, 92362306a36Sopenharmony_ci MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_SIZE, 92462306a36Sopenharmony_ci MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_HASH_INDEX, 92562306a36Sopenharmony_ci MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_COUNT, 92662306a36Sopenharmony_ci}; 92762306a36Sopenharmony_ci 92862306a36Sopenharmony_cienum mlxsw_sp_dpipe_table_adj_action { 92962306a36Sopenharmony_ci MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_DST_MAC, 93062306a36Sopenharmony_ci MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_ERIF_PORT, 93162306a36Sopenharmony_ci MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_COUNT, 93262306a36Sopenharmony_ci}; 93362306a36Sopenharmony_ci 93462306a36Sopenharmony_cistatic void 93562306a36Sopenharmony_cimlxsw_sp_dpipe_table_adj_match_action_prepare(struct devlink_dpipe_match *matches, 93662306a36Sopenharmony_ci struct devlink_dpipe_action *actions) 93762306a36Sopenharmony_ci{ 93862306a36Sopenharmony_ci struct devlink_dpipe_action *action; 93962306a36Sopenharmony_ci struct devlink_dpipe_match *match; 94062306a36Sopenharmony_ci 94162306a36Sopenharmony_ci match = &matches[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_INDEX]; 94262306a36Sopenharmony_ci match->type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT; 94362306a36Sopenharmony_ci match->header = &mlxsw_sp_dpipe_header_metadata; 94462306a36Sopenharmony_ci match->field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_INDEX; 94562306a36Sopenharmony_ci 94662306a36Sopenharmony_ci match = &matches[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_SIZE]; 94762306a36Sopenharmony_ci match->type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT; 94862306a36Sopenharmony_ci match->header = &mlxsw_sp_dpipe_header_metadata; 94962306a36Sopenharmony_ci match->field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_SIZE; 95062306a36Sopenharmony_ci 95162306a36Sopenharmony_ci match = &matches[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_HASH_INDEX]; 95262306a36Sopenharmony_ci match->type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT; 95362306a36Sopenharmony_ci match->header = &mlxsw_sp_dpipe_header_metadata; 95462306a36Sopenharmony_ci match->field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_HASH_INDEX; 95562306a36Sopenharmony_ci 95662306a36Sopenharmony_ci action = &actions[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_DST_MAC]; 95762306a36Sopenharmony_ci action->type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY; 95862306a36Sopenharmony_ci action->header = &devlink_dpipe_header_ethernet; 95962306a36Sopenharmony_ci action->field_id = DEVLINK_DPIPE_FIELD_ETHERNET_DST_MAC; 96062306a36Sopenharmony_ci 96162306a36Sopenharmony_ci action = &actions[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_ERIF_PORT]; 96262306a36Sopenharmony_ci action->type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY; 96362306a36Sopenharmony_ci action->header = &mlxsw_sp_dpipe_header_metadata; 96462306a36Sopenharmony_ci action->field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT; 96562306a36Sopenharmony_ci} 96662306a36Sopenharmony_ci 96762306a36Sopenharmony_cistatic int 96862306a36Sopenharmony_cimlxsw_sp_dpipe_table_adj_entry_prepare(struct devlink_dpipe_entry *entry, 96962306a36Sopenharmony_ci struct devlink_dpipe_value *match_values, 97062306a36Sopenharmony_ci struct devlink_dpipe_match *matches, 97162306a36Sopenharmony_ci struct devlink_dpipe_value *action_values, 97262306a36Sopenharmony_ci struct devlink_dpipe_action *actions) 97362306a36Sopenharmony_ci{ struct devlink_dpipe_value *action_value; 97462306a36Sopenharmony_ci struct devlink_dpipe_value *match_value; 97562306a36Sopenharmony_ci struct devlink_dpipe_action *action; 97662306a36Sopenharmony_ci struct devlink_dpipe_match *match; 97762306a36Sopenharmony_ci 97862306a36Sopenharmony_ci entry->match_values = match_values; 97962306a36Sopenharmony_ci entry->match_values_count = MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_COUNT; 98062306a36Sopenharmony_ci 98162306a36Sopenharmony_ci entry->action_values = action_values; 98262306a36Sopenharmony_ci entry->action_values_count = MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_COUNT; 98362306a36Sopenharmony_ci 98462306a36Sopenharmony_ci match = &matches[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_INDEX]; 98562306a36Sopenharmony_ci match_value = &match_values[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_INDEX]; 98662306a36Sopenharmony_ci 98762306a36Sopenharmony_ci match_value->match = match; 98862306a36Sopenharmony_ci match_value->value_size = sizeof(u32); 98962306a36Sopenharmony_ci match_value->value = kmalloc(match_value->value_size, GFP_KERNEL); 99062306a36Sopenharmony_ci if (!match_value->value) 99162306a36Sopenharmony_ci return -ENOMEM; 99262306a36Sopenharmony_ci 99362306a36Sopenharmony_ci match = &matches[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_SIZE]; 99462306a36Sopenharmony_ci match_value = &match_values[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_SIZE]; 99562306a36Sopenharmony_ci 99662306a36Sopenharmony_ci match_value->match = match; 99762306a36Sopenharmony_ci match_value->value_size = sizeof(u32); 99862306a36Sopenharmony_ci match_value->value = kmalloc(match_value->value_size, GFP_KERNEL); 99962306a36Sopenharmony_ci if (!match_value->value) 100062306a36Sopenharmony_ci return -ENOMEM; 100162306a36Sopenharmony_ci 100262306a36Sopenharmony_ci match = &matches[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_HASH_INDEX]; 100362306a36Sopenharmony_ci match_value = &match_values[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_HASH_INDEX]; 100462306a36Sopenharmony_ci 100562306a36Sopenharmony_ci match_value->match = match; 100662306a36Sopenharmony_ci match_value->value_size = sizeof(u32); 100762306a36Sopenharmony_ci match_value->value = kmalloc(match_value->value_size, GFP_KERNEL); 100862306a36Sopenharmony_ci if (!match_value->value) 100962306a36Sopenharmony_ci return -ENOMEM; 101062306a36Sopenharmony_ci 101162306a36Sopenharmony_ci action = &actions[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_DST_MAC]; 101262306a36Sopenharmony_ci action_value = &action_values[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_DST_MAC]; 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_ci action_value->action = action; 101562306a36Sopenharmony_ci action_value->value_size = sizeof(u64); 101662306a36Sopenharmony_ci action_value->value = kmalloc(action_value->value_size, GFP_KERNEL); 101762306a36Sopenharmony_ci if (!action_value->value) 101862306a36Sopenharmony_ci return -ENOMEM; 101962306a36Sopenharmony_ci 102062306a36Sopenharmony_ci action = &actions[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_ERIF_PORT]; 102162306a36Sopenharmony_ci action_value = &action_values[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_ERIF_PORT]; 102262306a36Sopenharmony_ci 102362306a36Sopenharmony_ci action_value->action = action; 102462306a36Sopenharmony_ci action_value->value_size = sizeof(u32); 102562306a36Sopenharmony_ci action_value->value = kmalloc(action_value->value_size, GFP_KERNEL); 102662306a36Sopenharmony_ci if (!action_value->value) 102762306a36Sopenharmony_ci return -ENOMEM; 102862306a36Sopenharmony_ci 102962306a36Sopenharmony_ci return 0; 103062306a36Sopenharmony_ci} 103162306a36Sopenharmony_ci 103262306a36Sopenharmony_cistatic void 103362306a36Sopenharmony_ci__mlxsw_sp_dpipe_table_adj_entry_fill(struct devlink_dpipe_entry *entry, 103462306a36Sopenharmony_ci u32 adj_index, u32 adj_size, 103562306a36Sopenharmony_ci u32 adj_hash_index, unsigned char *ha, 103662306a36Sopenharmony_ci struct mlxsw_sp_rif *rif) 103762306a36Sopenharmony_ci{ 103862306a36Sopenharmony_ci struct devlink_dpipe_value *value; 103962306a36Sopenharmony_ci u32 *p_rif_value; 104062306a36Sopenharmony_ci u32 *p_index; 104162306a36Sopenharmony_ci 104262306a36Sopenharmony_ci value = &entry->match_values[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_INDEX]; 104362306a36Sopenharmony_ci p_index = value->value; 104462306a36Sopenharmony_ci *p_index = adj_index; 104562306a36Sopenharmony_ci 104662306a36Sopenharmony_ci value = &entry->match_values[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_SIZE]; 104762306a36Sopenharmony_ci p_index = value->value; 104862306a36Sopenharmony_ci *p_index = adj_size; 104962306a36Sopenharmony_ci 105062306a36Sopenharmony_ci value = &entry->match_values[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_HASH_INDEX]; 105162306a36Sopenharmony_ci p_index = value->value; 105262306a36Sopenharmony_ci *p_index = adj_hash_index; 105362306a36Sopenharmony_ci 105462306a36Sopenharmony_ci value = &entry->action_values[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_DST_MAC]; 105562306a36Sopenharmony_ci ether_addr_copy(value->value, ha); 105662306a36Sopenharmony_ci 105762306a36Sopenharmony_ci value = &entry->action_values[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_ERIF_PORT]; 105862306a36Sopenharmony_ci p_rif_value = value->value; 105962306a36Sopenharmony_ci *p_rif_value = mlxsw_sp_rif_index(rif); 106062306a36Sopenharmony_ci value->mapping_value = mlxsw_sp_rif_dev_ifindex(rif); 106162306a36Sopenharmony_ci value->mapping_valid = true; 106262306a36Sopenharmony_ci} 106362306a36Sopenharmony_ci 106462306a36Sopenharmony_cistatic void mlxsw_sp_dpipe_table_adj_entry_fill(struct mlxsw_sp *mlxsw_sp, 106562306a36Sopenharmony_ci struct mlxsw_sp_nexthop *nh, 106662306a36Sopenharmony_ci struct devlink_dpipe_entry *entry) 106762306a36Sopenharmony_ci{ 106862306a36Sopenharmony_ci struct mlxsw_sp_rif *rif = mlxsw_sp_nexthop_rif(nh); 106962306a36Sopenharmony_ci unsigned char *ha = mlxsw_sp_nexthop_ha(nh); 107062306a36Sopenharmony_ci u32 adj_hash_index = 0; 107162306a36Sopenharmony_ci u32 adj_index = 0; 107262306a36Sopenharmony_ci u32 adj_size = 0; 107362306a36Sopenharmony_ci int err; 107462306a36Sopenharmony_ci 107562306a36Sopenharmony_ci mlxsw_sp_nexthop_indexes(nh, &adj_index, &adj_size, &adj_hash_index); 107662306a36Sopenharmony_ci __mlxsw_sp_dpipe_table_adj_entry_fill(entry, adj_index, adj_size, 107762306a36Sopenharmony_ci adj_hash_index, ha, rif); 107862306a36Sopenharmony_ci err = mlxsw_sp_nexthop_counter_get(mlxsw_sp, nh, &entry->counter); 107962306a36Sopenharmony_ci if (!err) 108062306a36Sopenharmony_ci entry->counter_valid = true; 108162306a36Sopenharmony_ci} 108262306a36Sopenharmony_ci 108362306a36Sopenharmony_cistatic int 108462306a36Sopenharmony_cimlxsw_sp_dpipe_table_adj_entries_get(struct mlxsw_sp *mlxsw_sp, 108562306a36Sopenharmony_ci struct devlink_dpipe_entry *entry, 108662306a36Sopenharmony_ci bool counters_enabled, 108762306a36Sopenharmony_ci struct devlink_dpipe_dump_ctx *dump_ctx) 108862306a36Sopenharmony_ci{ 108962306a36Sopenharmony_ci struct mlxsw_sp_nexthop *nh; 109062306a36Sopenharmony_ci int entry_index = 0; 109162306a36Sopenharmony_ci int nh_count_max; 109262306a36Sopenharmony_ci int nh_count = 0; 109362306a36Sopenharmony_ci int nh_skip; 109462306a36Sopenharmony_ci int j; 109562306a36Sopenharmony_ci int err; 109662306a36Sopenharmony_ci 109762306a36Sopenharmony_ci mutex_lock(&mlxsw_sp->router->lock); 109862306a36Sopenharmony_ci nh_count_max = mlxsw_sp_dpipe_table_adj_size(mlxsw_sp); 109962306a36Sopenharmony_cistart_again: 110062306a36Sopenharmony_ci err = devlink_dpipe_entry_ctx_prepare(dump_ctx); 110162306a36Sopenharmony_ci if (err) 110262306a36Sopenharmony_ci goto err_ctx_prepare; 110362306a36Sopenharmony_ci j = 0; 110462306a36Sopenharmony_ci nh_skip = nh_count; 110562306a36Sopenharmony_ci nh_count = 0; 110662306a36Sopenharmony_ci mlxsw_sp_nexthop_for_each(nh, mlxsw_sp->router) { 110762306a36Sopenharmony_ci if (!mlxsw_sp_nexthop_is_forward(nh) || 110862306a36Sopenharmony_ci mlxsw_sp_nexthop_group_has_ipip(nh)) 110962306a36Sopenharmony_ci continue; 111062306a36Sopenharmony_ci 111162306a36Sopenharmony_ci if (nh_count < nh_skip) 111262306a36Sopenharmony_ci goto skip; 111362306a36Sopenharmony_ci 111462306a36Sopenharmony_ci mlxsw_sp_dpipe_table_adj_entry_fill(mlxsw_sp, nh, entry); 111562306a36Sopenharmony_ci entry->index = entry_index; 111662306a36Sopenharmony_ci err = devlink_dpipe_entry_ctx_append(dump_ctx, entry); 111762306a36Sopenharmony_ci if (err) { 111862306a36Sopenharmony_ci if (err == -EMSGSIZE) { 111962306a36Sopenharmony_ci if (!j) 112062306a36Sopenharmony_ci goto err_entry_append; 112162306a36Sopenharmony_ci break; 112262306a36Sopenharmony_ci } 112362306a36Sopenharmony_ci goto err_entry_append; 112462306a36Sopenharmony_ci } 112562306a36Sopenharmony_ci entry_index++; 112662306a36Sopenharmony_ci j++; 112762306a36Sopenharmony_ciskip: 112862306a36Sopenharmony_ci nh_count++; 112962306a36Sopenharmony_ci } 113062306a36Sopenharmony_ci 113162306a36Sopenharmony_ci devlink_dpipe_entry_ctx_close(dump_ctx); 113262306a36Sopenharmony_ci if (nh_count != nh_count_max) 113362306a36Sopenharmony_ci goto start_again; 113462306a36Sopenharmony_ci mutex_unlock(&mlxsw_sp->router->lock); 113562306a36Sopenharmony_ci 113662306a36Sopenharmony_ci return 0; 113762306a36Sopenharmony_ci 113862306a36Sopenharmony_cierr_ctx_prepare: 113962306a36Sopenharmony_cierr_entry_append: 114062306a36Sopenharmony_ci mutex_unlock(&mlxsw_sp->router->lock); 114162306a36Sopenharmony_ci return err; 114262306a36Sopenharmony_ci} 114362306a36Sopenharmony_ci 114462306a36Sopenharmony_cistatic int 114562306a36Sopenharmony_cimlxsw_sp_dpipe_table_adj_entries_dump(void *priv, bool counters_enabled, 114662306a36Sopenharmony_ci struct devlink_dpipe_dump_ctx *dump_ctx) 114762306a36Sopenharmony_ci{ 114862306a36Sopenharmony_ci struct devlink_dpipe_value action_values[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_COUNT]; 114962306a36Sopenharmony_ci struct devlink_dpipe_value match_values[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_COUNT]; 115062306a36Sopenharmony_ci struct devlink_dpipe_action actions[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_COUNT]; 115162306a36Sopenharmony_ci struct devlink_dpipe_match matches[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_COUNT]; 115262306a36Sopenharmony_ci struct devlink_dpipe_entry entry = {0}; 115362306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = priv; 115462306a36Sopenharmony_ci int err; 115562306a36Sopenharmony_ci 115662306a36Sopenharmony_ci memset(matches, 0, MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_COUNT * 115762306a36Sopenharmony_ci sizeof(matches[0])); 115862306a36Sopenharmony_ci memset(match_values, 0, MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_COUNT * 115962306a36Sopenharmony_ci sizeof(match_values[0])); 116062306a36Sopenharmony_ci memset(actions, 0, MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_COUNT * 116162306a36Sopenharmony_ci sizeof(actions[0])); 116262306a36Sopenharmony_ci memset(action_values, 0, MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_COUNT * 116362306a36Sopenharmony_ci sizeof(action_values[0])); 116462306a36Sopenharmony_ci 116562306a36Sopenharmony_ci mlxsw_sp_dpipe_table_adj_match_action_prepare(matches, actions); 116662306a36Sopenharmony_ci err = mlxsw_sp_dpipe_table_adj_entry_prepare(&entry, 116762306a36Sopenharmony_ci match_values, matches, 116862306a36Sopenharmony_ci action_values, actions); 116962306a36Sopenharmony_ci if (err) 117062306a36Sopenharmony_ci goto out; 117162306a36Sopenharmony_ci 117262306a36Sopenharmony_ci err = mlxsw_sp_dpipe_table_adj_entries_get(mlxsw_sp, &entry, 117362306a36Sopenharmony_ci counters_enabled, dump_ctx); 117462306a36Sopenharmony_ciout: 117562306a36Sopenharmony_ci devlink_dpipe_entry_clear(&entry); 117662306a36Sopenharmony_ci return err; 117762306a36Sopenharmony_ci} 117862306a36Sopenharmony_ci 117962306a36Sopenharmony_cistatic int mlxsw_sp_dpipe_table_adj_counters_update(void *priv, bool enable) 118062306a36Sopenharmony_ci{ 118162306a36Sopenharmony_ci char ratr_pl[MLXSW_REG_RATR_LEN]; 118262306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = priv; 118362306a36Sopenharmony_ci struct mlxsw_sp_nexthop *nh; 118462306a36Sopenharmony_ci u32 adj_hash_index = 0; 118562306a36Sopenharmony_ci u32 adj_index = 0; 118662306a36Sopenharmony_ci u32 adj_size = 0; 118762306a36Sopenharmony_ci 118862306a36Sopenharmony_ci mlxsw_sp_nexthop_for_each(nh, mlxsw_sp->router) { 118962306a36Sopenharmony_ci if (!mlxsw_sp_nexthop_is_forward(nh) || 119062306a36Sopenharmony_ci mlxsw_sp_nexthop_group_has_ipip(nh)) 119162306a36Sopenharmony_ci continue; 119262306a36Sopenharmony_ci 119362306a36Sopenharmony_ci mlxsw_sp_nexthop_indexes(nh, &adj_index, &adj_size, 119462306a36Sopenharmony_ci &adj_hash_index); 119562306a36Sopenharmony_ci if (enable) 119662306a36Sopenharmony_ci mlxsw_sp_nexthop_counter_alloc(mlxsw_sp, nh); 119762306a36Sopenharmony_ci else 119862306a36Sopenharmony_ci mlxsw_sp_nexthop_counter_free(mlxsw_sp, nh); 119962306a36Sopenharmony_ci mlxsw_sp_nexthop_eth_update(mlxsw_sp, 120062306a36Sopenharmony_ci adj_index + adj_hash_index, nh, 120162306a36Sopenharmony_ci true, ratr_pl); 120262306a36Sopenharmony_ci } 120362306a36Sopenharmony_ci return 0; 120462306a36Sopenharmony_ci} 120562306a36Sopenharmony_ci 120662306a36Sopenharmony_cistatic u64 120762306a36Sopenharmony_cimlxsw_sp_dpipe_table_adj_size_get(void *priv) 120862306a36Sopenharmony_ci{ 120962306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = priv; 121062306a36Sopenharmony_ci u64 size; 121162306a36Sopenharmony_ci 121262306a36Sopenharmony_ci mutex_lock(&mlxsw_sp->router->lock); 121362306a36Sopenharmony_ci size = mlxsw_sp_dpipe_table_adj_size(mlxsw_sp); 121462306a36Sopenharmony_ci mutex_unlock(&mlxsw_sp->router->lock); 121562306a36Sopenharmony_ci 121662306a36Sopenharmony_ci return size; 121762306a36Sopenharmony_ci} 121862306a36Sopenharmony_ci 121962306a36Sopenharmony_cistatic struct devlink_dpipe_table_ops mlxsw_sp_dpipe_table_adj_ops = { 122062306a36Sopenharmony_ci .matches_dump = mlxsw_sp_dpipe_table_adj_matches_dump, 122162306a36Sopenharmony_ci .actions_dump = mlxsw_sp_dpipe_table_adj_actions_dump, 122262306a36Sopenharmony_ci .entries_dump = mlxsw_sp_dpipe_table_adj_entries_dump, 122362306a36Sopenharmony_ci .counters_set_update = mlxsw_sp_dpipe_table_adj_counters_update, 122462306a36Sopenharmony_ci .size_get = mlxsw_sp_dpipe_table_adj_size_get, 122562306a36Sopenharmony_ci}; 122662306a36Sopenharmony_ci 122762306a36Sopenharmony_ci#define MLXSW_SP_DPIPE_TABLE_RESOURCE_UNIT_ADJ 1 122862306a36Sopenharmony_ci 122962306a36Sopenharmony_cistatic int mlxsw_sp_dpipe_adj_table_init(struct mlxsw_sp *mlxsw_sp) 123062306a36Sopenharmony_ci{ 123162306a36Sopenharmony_ci struct devlink *devlink = priv_to_devlink(mlxsw_sp->core); 123262306a36Sopenharmony_ci int err; 123362306a36Sopenharmony_ci 123462306a36Sopenharmony_ci err = devl_dpipe_table_register(devlink, 123562306a36Sopenharmony_ci MLXSW_SP_DPIPE_TABLE_NAME_ADJ, 123662306a36Sopenharmony_ci &mlxsw_sp_dpipe_table_adj_ops, 123762306a36Sopenharmony_ci mlxsw_sp, false); 123862306a36Sopenharmony_ci if (err) 123962306a36Sopenharmony_ci return err; 124062306a36Sopenharmony_ci 124162306a36Sopenharmony_ci err = devl_dpipe_table_resource_set(devlink, 124262306a36Sopenharmony_ci MLXSW_SP_DPIPE_TABLE_NAME_ADJ, 124362306a36Sopenharmony_ci MLXSW_SP_RESOURCE_KVD_LINEAR, 124462306a36Sopenharmony_ci MLXSW_SP_DPIPE_TABLE_RESOURCE_UNIT_ADJ); 124562306a36Sopenharmony_ci if (err) 124662306a36Sopenharmony_ci goto err_resource_set; 124762306a36Sopenharmony_ci 124862306a36Sopenharmony_ci return 0; 124962306a36Sopenharmony_ci 125062306a36Sopenharmony_cierr_resource_set: 125162306a36Sopenharmony_ci devl_dpipe_table_unregister(devlink, 125262306a36Sopenharmony_ci MLXSW_SP_DPIPE_TABLE_NAME_ADJ); 125362306a36Sopenharmony_ci return err; 125462306a36Sopenharmony_ci} 125562306a36Sopenharmony_ci 125662306a36Sopenharmony_cistatic void mlxsw_sp_dpipe_adj_table_fini(struct mlxsw_sp *mlxsw_sp) 125762306a36Sopenharmony_ci{ 125862306a36Sopenharmony_ci struct devlink *devlink = priv_to_devlink(mlxsw_sp->core); 125962306a36Sopenharmony_ci 126062306a36Sopenharmony_ci devl_dpipe_table_unregister(devlink, 126162306a36Sopenharmony_ci MLXSW_SP_DPIPE_TABLE_NAME_ADJ); 126262306a36Sopenharmony_ci} 126362306a36Sopenharmony_ci 126462306a36Sopenharmony_ciint mlxsw_sp_dpipe_init(struct mlxsw_sp *mlxsw_sp) 126562306a36Sopenharmony_ci{ 126662306a36Sopenharmony_ci struct devlink *devlink = priv_to_devlink(mlxsw_sp->core); 126762306a36Sopenharmony_ci int err; 126862306a36Sopenharmony_ci 126962306a36Sopenharmony_ci devl_dpipe_headers_register(devlink, &mlxsw_sp_dpipe_headers); 127062306a36Sopenharmony_ci 127162306a36Sopenharmony_ci err = mlxsw_sp_dpipe_erif_table_init(mlxsw_sp); 127262306a36Sopenharmony_ci if (err) 127362306a36Sopenharmony_ci goto err_erif_table_init; 127462306a36Sopenharmony_ci 127562306a36Sopenharmony_ci err = mlxsw_sp_dpipe_host4_table_init(mlxsw_sp); 127662306a36Sopenharmony_ci if (err) 127762306a36Sopenharmony_ci goto err_host4_table_init; 127862306a36Sopenharmony_ci 127962306a36Sopenharmony_ci err = mlxsw_sp_dpipe_host6_table_init(mlxsw_sp); 128062306a36Sopenharmony_ci if (err) 128162306a36Sopenharmony_ci goto err_host6_table_init; 128262306a36Sopenharmony_ci 128362306a36Sopenharmony_ci err = mlxsw_sp_dpipe_adj_table_init(mlxsw_sp); 128462306a36Sopenharmony_ci if (err) 128562306a36Sopenharmony_ci goto err_adj_table_init; 128662306a36Sopenharmony_ci 128762306a36Sopenharmony_ci return 0; 128862306a36Sopenharmony_cierr_adj_table_init: 128962306a36Sopenharmony_ci mlxsw_sp_dpipe_host6_table_fini(mlxsw_sp); 129062306a36Sopenharmony_cierr_host6_table_init: 129162306a36Sopenharmony_ci mlxsw_sp_dpipe_host4_table_fini(mlxsw_sp); 129262306a36Sopenharmony_cierr_host4_table_init: 129362306a36Sopenharmony_ci mlxsw_sp_dpipe_erif_table_fini(mlxsw_sp); 129462306a36Sopenharmony_cierr_erif_table_init: 129562306a36Sopenharmony_ci devl_dpipe_headers_unregister(priv_to_devlink(mlxsw_sp->core)); 129662306a36Sopenharmony_ci return err; 129762306a36Sopenharmony_ci} 129862306a36Sopenharmony_ci 129962306a36Sopenharmony_civoid mlxsw_sp_dpipe_fini(struct mlxsw_sp *mlxsw_sp) 130062306a36Sopenharmony_ci{ 130162306a36Sopenharmony_ci struct devlink *devlink = priv_to_devlink(mlxsw_sp->core); 130262306a36Sopenharmony_ci 130362306a36Sopenharmony_ci mlxsw_sp_dpipe_adj_table_fini(mlxsw_sp); 130462306a36Sopenharmony_ci mlxsw_sp_dpipe_host6_table_fini(mlxsw_sp); 130562306a36Sopenharmony_ci mlxsw_sp_dpipe_host4_table_fini(mlxsw_sp); 130662306a36Sopenharmony_ci mlxsw_sp_dpipe_erif_table_fini(mlxsw_sp); 130762306a36Sopenharmony_ci devl_dpipe_headers_unregister(devlink); 130862306a36Sopenharmony_ci} 1309