mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-23 01:10:04 +00:00
Merge branch 'mlxsw-Add-router-adjacency-dpipe-table'
Jiri Pirko says: ==================== mlxsw: Add router adjacency dpipe table Arkadi says: This patchset adds router adjacency dpipe table support. This will provide the ability to observe the hardware offloaded IPv4/6 nexthops. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
f6fc5b494d
5 changed files with 572 additions and 24 deletions
|
@ -4549,6 +4549,27 @@ MLXSW_ITEM32(reg, ratr, ipip_ipv4_udip, 0x18, 0, 32);
|
|||
*/
|
||||
MLXSW_ITEM32(reg, ratr, ipip_ipv6_ptr, 0x1C, 0, 24);
|
||||
|
||||
enum mlxsw_reg_flow_counter_set_type {
|
||||
/* No count */
|
||||
MLXSW_REG_FLOW_COUNTER_SET_TYPE_NO_COUNT = 0x00,
|
||||
/* Count packets and bytes */
|
||||
MLXSW_REG_FLOW_COUNTER_SET_TYPE_PACKETS_BYTES = 0x03,
|
||||
/* Count only packets */
|
||||
MLXSW_REG_FLOW_COUNTER_SET_TYPE_PACKETS = 0x05,
|
||||
};
|
||||
|
||||
/* reg_ratr_counter_set_type
|
||||
* Counter set type for flow counters
|
||||
* Access: RW
|
||||
*/
|
||||
MLXSW_ITEM32(reg, ratr, counter_set_type, 0x28, 24, 8);
|
||||
|
||||
/* reg_ratr_counter_index
|
||||
* Counter index for flow counters
|
||||
* Access: RW
|
||||
*/
|
||||
MLXSW_ITEM32(reg, ratr, counter_index, 0x28, 0, 24);
|
||||
|
||||
static inline void
|
||||
mlxsw_reg_ratr_pack(char *payload,
|
||||
enum mlxsw_reg_ratr_op op, bool valid,
|
||||
|
@ -4576,6 +4597,20 @@ static inline void mlxsw_reg_ratr_ipip4_entry_pack(char *payload, u32 ipv4_udip)
|
|||
mlxsw_reg_ratr_ipip_ipv4_udip_set(payload, ipv4_udip);
|
||||
}
|
||||
|
||||
static inline void mlxsw_reg_ratr_counter_pack(char *payload, u64 counter_index,
|
||||
bool counter_enable)
|
||||
{
|
||||
enum mlxsw_reg_flow_counter_set_type set_type;
|
||||
|
||||
if (counter_enable)
|
||||
set_type = MLXSW_REG_FLOW_COUNTER_SET_TYPE_PACKETS_BYTES;
|
||||
else
|
||||
set_type = MLXSW_REG_FLOW_COUNTER_SET_TYPE_NO_COUNT;
|
||||
|
||||
mlxsw_reg_ratr_counter_index_set(payload, counter_index);
|
||||
mlxsw_reg_ratr_counter_set_type_set(payload, set_type);
|
||||
}
|
||||
|
||||
/* RICNT - Router Interface Counter Register
|
||||
* -----------------------------------------
|
||||
* The RICNT register retrieves per port performance counters
|
||||
|
@ -5297,15 +5332,6 @@ enum mlxsw_reg_rauht_trap_id {
|
|||
*/
|
||||
MLXSW_ITEM32(reg, rauht, trap_id, 0x60, 0, 9);
|
||||
|
||||
enum mlxsw_reg_flow_counter_set_type {
|
||||
/* No count */
|
||||
MLXSW_REG_FLOW_COUNTER_SET_TYPE_NO_COUNT = 0x00,
|
||||
/* Count packets and bytes */
|
||||
MLXSW_REG_FLOW_COUNTER_SET_TYPE_PACKETS_BYTES = 0x03,
|
||||
/* Count only packets */
|
||||
MLXSW_REG_FLOW_COUNTER_SET_TYPE_PACKETS = 0x05,
|
||||
};
|
||||
|
||||
/* reg_rauht_counter_set_type
|
||||
* Counter set type for flow counters
|
||||
* Access: RW
|
||||
|
|
|
@ -43,21 +43,36 @@ enum mlxsw_sp_field_metadata_id {
|
|||
MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT,
|
||||
MLXSW_SP_DPIPE_FIELD_METADATA_L3_FORWARD,
|
||||
MLXSW_SP_DPIPE_FIELD_METADATA_L3_DROP,
|
||||
MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_INDEX,
|
||||
MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_HASH_INDEX,
|
||||
};
|
||||
|
||||
static struct devlink_dpipe_field mlxsw_sp_dpipe_fields_metadata[] = {
|
||||
{ .name = "erif_port",
|
||||
.id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT,
|
||||
.bitwidth = 32,
|
||||
.mapping_type = DEVLINK_DPIPE_FIELD_MAPPING_TYPE_IFINDEX,
|
||||
{
|
||||
.name = "erif_port",
|
||||
.id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT,
|
||||
.bitwidth = 32,
|
||||
.mapping_type = DEVLINK_DPIPE_FIELD_MAPPING_TYPE_IFINDEX,
|
||||
},
|
||||
{ .name = "l3_forward",
|
||||
.id = MLXSW_SP_DPIPE_FIELD_METADATA_L3_FORWARD,
|
||||
.bitwidth = 1,
|
||||
{
|
||||
.name = "l3_forward",
|
||||
.id = MLXSW_SP_DPIPE_FIELD_METADATA_L3_FORWARD,
|
||||
.bitwidth = 1,
|
||||
},
|
||||
{ .name = "l3_drop",
|
||||
.id = MLXSW_SP_DPIPE_FIELD_METADATA_L3_DROP,
|
||||
.bitwidth = 1,
|
||||
{
|
||||
.name = "l3_drop",
|
||||
.id = MLXSW_SP_DPIPE_FIELD_METADATA_L3_DROP,
|
||||
.bitwidth = 1,
|
||||
},
|
||||
{
|
||||
.name = "adj_index",
|
||||
.id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_INDEX,
|
||||
.bitwidth = 32,
|
||||
},
|
||||
{
|
||||
.name = "adj_hash_index",
|
||||
.id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_HASH_INDEX,
|
||||
.bitwidth = 32,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -826,6 +841,359 @@ static void mlxsw_sp_dpipe_host6_table_fini(struct mlxsw_sp *mlxsw_sp)
|
|||
MLXSW_SP_DPIPE_TABLE_NAME_HOST6);
|
||||
}
|
||||
|
||||
static int mlxsw_sp_dpipe_table_adj_matches_dump(void *priv,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct devlink_dpipe_match match = {0};
|
||||
int err;
|
||||
|
||||
match.type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
|
||||
match.header = &mlxsw_sp_dpipe_header_metadata;
|
||||
match.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_INDEX;
|
||||
|
||||
err = devlink_dpipe_match_put(skb, &match);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
match.type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
|
||||
match.header = &mlxsw_sp_dpipe_header_metadata;
|
||||
match.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_HASH_INDEX;
|
||||
|
||||
return devlink_dpipe_match_put(skb, &match);
|
||||
}
|
||||
|
||||
static int mlxsw_sp_dpipe_table_adj_actions_dump(void *priv,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct devlink_dpipe_action action = {0};
|
||||
int err;
|
||||
|
||||
action.type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY;
|
||||
action.header = &devlink_dpipe_header_ethernet;
|
||||
action.field_id = DEVLINK_DPIPE_FIELD_ETHERNET_DST_MAC;
|
||||
|
||||
err = devlink_dpipe_action_put(skb, &action);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
action.type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY;
|
||||
action.header = &mlxsw_sp_dpipe_header_metadata;
|
||||
action.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT;
|
||||
|
||||
return devlink_dpipe_action_put(skb, &action);
|
||||
}
|
||||
|
||||
static u64 mlxsw_sp_dpipe_table_adj_size(struct mlxsw_sp *mlxsw_sp)
|
||||
{
|
||||
struct mlxsw_sp_nexthop *nh;
|
||||
u64 size = 0;
|
||||
|
||||
mlxsw_sp_nexthop_for_each(nh, mlxsw_sp->router)
|
||||
if (mlxsw_sp_nexthop_offload(nh) &&
|
||||
!mlxsw_sp_nexthop_group_has_ipip(nh))
|
||||
size++;
|
||||
return size;
|
||||
}
|
||||
|
||||
enum mlxsw_sp_dpipe_table_adj_match {
|
||||
MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_INDEX,
|
||||
MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_HASH_INDEX,
|
||||
MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_COUNT,
|
||||
};
|
||||
|
||||
enum mlxsw_sp_dpipe_table_adj_action {
|
||||
MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_DST_MAC,
|
||||
MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_ERIF_PORT,
|
||||
MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_COUNT,
|
||||
};
|
||||
|
||||
static void
|
||||
mlxsw_sp_dpipe_table_adj_match_action_prepare(struct devlink_dpipe_match *matches,
|
||||
struct devlink_dpipe_action *actions)
|
||||
{
|
||||
struct devlink_dpipe_action *action;
|
||||
struct devlink_dpipe_match *match;
|
||||
|
||||
match = &matches[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_INDEX];
|
||||
match->type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
|
||||
match->header = &mlxsw_sp_dpipe_header_metadata;
|
||||
match->field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_INDEX;
|
||||
|
||||
match = &matches[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_HASH_INDEX];
|
||||
match->type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
|
||||
match->header = &mlxsw_sp_dpipe_header_metadata;
|
||||
match->field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_HASH_INDEX;
|
||||
|
||||
action = &actions[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_DST_MAC];
|
||||
action->type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY;
|
||||
action->header = &devlink_dpipe_header_ethernet;
|
||||
action->field_id = DEVLINK_DPIPE_FIELD_ETHERNET_DST_MAC;
|
||||
|
||||
action = &actions[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_ERIF_PORT];
|
||||
action->type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY;
|
||||
action->header = &mlxsw_sp_dpipe_header_metadata;
|
||||
action->field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT;
|
||||
}
|
||||
|
||||
static int
|
||||
mlxsw_sp_dpipe_table_adj_entry_prepare(struct devlink_dpipe_entry *entry,
|
||||
struct devlink_dpipe_value *match_values,
|
||||
struct devlink_dpipe_match *matches,
|
||||
struct devlink_dpipe_value *action_values,
|
||||
struct devlink_dpipe_action *actions)
|
||||
{ struct devlink_dpipe_value *action_value;
|
||||
struct devlink_dpipe_value *match_value;
|
||||
struct devlink_dpipe_action *action;
|
||||
struct devlink_dpipe_match *match;
|
||||
|
||||
entry->match_values = match_values;
|
||||
entry->match_values_count = MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_COUNT;
|
||||
|
||||
entry->action_values = action_values;
|
||||
entry->action_values_count = MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_COUNT;
|
||||
|
||||
match = &matches[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_INDEX];
|
||||
match_value = &match_values[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_INDEX];
|
||||
|
||||
match_value->match = match;
|
||||
match_value->value_size = sizeof(u32);
|
||||
match_value->value = kmalloc(match_value->value_size, GFP_KERNEL);
|
||||
if (!match_value->value)
|
||||
return -ENOMEM;
|
||||
|
||||
match = &matches[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_HASH_INDEX];
|
||||
match_value = &match_values[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_HASH_INDEX];
|
||||
|
||||
match_value->match = match;
|
||||
match_value->value_size = sizeof(u32);
|
||||
match_value->value = kmalloc(match_value->value_size, GFP_KERNEL);
|
||||
if (!match_value->value)
|
||||
return -ENOMEM;
|
||||
|
||||
action = &actions[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_DST_MAC];
|
||||
action_value = &action_values[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_DST_MAC];
|
||||
|
||||
action_value->action = action;
|
||||
action_value->value_size = sizeof(u64);
|
||||
action_value->value = kmalloc(action_value->value_size, GFP_KERNEL);
|
||||
if (!action_value->value)
|
||||
return -ENOMEM;
|
||||
|
||||
action = &actions[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_ERIF_PORT];
|
||||
action_value = &action_values[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_ERIF_PORT];
|
||||
|
||||
action_value->action = action;
|
||||
action_value->value_size = sizeof(u32);
|
||||
action_value->value = kmalloc(action_value->value_size, GFP_KERNEL);
|
||||
if (!action_value->value)
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
__mlxsw_sp_dpipe_table_adj_entry_fill(struct devlink_dpipe_entry *entry,
|
||||
u32 adj_index, u32 adj_hash_index,
|
||||
unsigned char *ha,
|
||||
struct mlxsw_sp_rif *rif)
|
||||
{
|
||||
struct devlink_dpipe_value *value;
|
||||
u32 *p_rif_value;
|
||||
u32 *p_index;
|
||||
|
||||
value = &entry->match_values[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_INDEX];
|
||||
p_index = value->value;
|
||||
*p_index = adj_index;
|
||||
|
||||
value = &entry->match_values[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_HASH_INDEX];
|
||||
p_index = value->value;
|
||||
*p_index = adj_hash_index;
|
||||
|
||||
value = &entry->action_values[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_DST_MAC];
|
||||
ether_addr_copy(value->value, ha);
|
||||
|
||||
value = &entry->action_values[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_ERIF_PORT];
|
||||
p_rif_value = value->value;
|
||||
*p_rif_value = mlxsw_sp_rif_index(rif);
|
||||
value->mapping_value = mlxsw_sp_rif_dev_ifindex(rif);
|
||||
value->mapping_valid = true;
|
||||
}
|
||||
|
||||
static void mlxsw_sp_dpipe_table_adj_entry_fill(struct mlxsw_sp *mlxsw_sp,
|
||||
struct mlxsw_sp_nexthop *nh,
|
||||
struct devlink_dpipe_entry *entry)
|
||||
{
|
||||
struct mlxsw_sp_rif *rif = mlxsw_sp_nexthop_rif(nh);
|
||||
unsigned char *ha = mlxsw_sp_nexthop_ha(nh);
|
||||
u32 adj_hash_index = 0;
|
||||
u32 adj_index = 0;
|
||||
int err;
|
||||
|
||||
mlxsw_sp_nexthop_indexes(nh, &adj_index, &adj_hash_index);
|
||||
__mlxsw_sp_dpipe_table_adj_entry_fill(entry, adj_index,
|
||||
adj_hash_index, ha, rif);
|
||||
err = mlxsw_sp_nexthop_counter_get(mlxsw_sp, nh, &entry->counter);
|
||||
if (!err)
|
||||
entry->counter_valid = true;
|
||||
}
|
||||
|
||||
static int
|
||||
mlxsw_sp_dpipe_table_adj_entries_get(struct mlxsw_sp *mlxsw_sp,
|
||||
struct devlink_dpipe_entry *entry,
|
||||
bool counters_enabled,
|
||||
struct devlink_dpipe_dump_ctx *dump_ctx)
|
||||
{
|
||||
struct mlxsw_sp_nexthop *nh;
|
||||
int entry_index = 0;
|
||||
int nh_count_max;
|
||||
int nh_count = 0;
|
||||
int nh_skip;
|
||||
int j;
|
||||
int err;
|
||||
|
||||
rtnl_lock();
|
||||
nh_count_max = mlxsw_sp_dpipe_table_adj_size(mlxsw_sp);
|
||||
start_again:
|
||||
err = devlink_dpipe_entry_ctx_prepare(dump_ctx);
|
||||
if (err)
|
||||
goto err_ctx_prepare;
|
||||
j = 0;
|
||||
nh_skip = nh_count;
|
||||
mlxsw_sp_nexthop_for_each(nh, mlxsw_sp->router) {
|
||||
if (!mlxsw_sp_nexthop_offload(nh) ||
|
||||
mlxsw_sp_nexthop_group_has_ipip(nh))
|
||||
continue;
|
||||
|
||||
if (nh_count < nh_skip)
|
||||
goto skip;
|
||||
|
||||
mlxsw_sp_dpipe_table_adj_entry_fill(mlxsw_sp, nh, entry);
|
||||
entry->index = entry_index;
|
||||
err = devlink_dpipe_entry_ctx_append(dump_ctx, entry);
|
||||
if (err) {
|
||||
if (err == -EMSGSIZE) {
|
||||
if (!j)
|
||||
goto err_entry_append;
|
||||
break;
|
||||
}
|
||||
goto err_entry_append;
|
||||
}
|
||||
entry_index++;
|
||||
j++;
|
||||
skip:
|
||||
nh_count++;
|
||||
}
|
||||
|
||||
devlink_dpipe_entry_ctx_close(dump_ctx);
|
||||
if (nh_count != nh_count_max)
|
||||
goto start_again;
|
||||
rtnl_unlock();
|
||||
|
||||
return 0;
|
||||
|
||||
err_ctx_prepare:
|
||||
err_entry_append:
|
||||
rtnl_unlock();
|
||||
return err;
|
||||
}
|
||||
|
||||
static int
|
||||
mlxsw_sp_dpipe_table_adj_entries_dump(void *priv, bool counters_enabled,
|
||||
struct devlink_dpipe_dump_ctx *dump_ctx)
|
||||
{
|
||||
struct devlink_dpipe_value action_values[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_COUNT];
|
||||
struct devlink_dpipe_value match_values[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_COUNT];
|
||||
struct devlink_dpipe_action actions[MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_COUNT];
|
||||
struct devlink_dpipe_match matches[MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_COUNT];
|
||||
struct devlink_dpipe_entry entry = {0};
|
||||
struct mlxsw_sp *mlxsw_sp = priv;
|
||||
int err;
|
||||
|
||||
memset(matches, 0, MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_COUNT *
|
||||
sizeof(matches[0]));
|
||||
memset(match_values, 0, MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_COUNT *
|
||||
sizeof(match_values[0]));
|
||||
memset(actions, 0, MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_COUNT *
|
||||
sizeof(actions[0]));
|
||||
memset(action_values, 0, MLXSW_SP_DPIPE_TABLE_ADJ_ACTION_COUNT *
|
||||
sizeof(action_values[0]));
|
||||
|
||||
mlxsw_sp_dpipe_table_adj_match_action_prepare(matches, actions);
|
||||
err = mlxsw_sp_dpipe_table_adj_entry_prepare(&entry,
|
||||
match_values, matches,
|
||||
action_values, actions);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
err = mlxsw_sp_dpipe_table_adj_entries_get(mlxsw_sp, &entry,
|
||||
counters_enabled, dump_ctx);
|
||||
out:
|
||||
devlink_dpipe_entry_clear(&entry);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int mlxsw_sp_dpipe_table_adj_counters_update(void *priv, bool enable)
|
||||
{
|
||||
struct mlxsw_sp *mlxsw_sp = priv;
|
||||
struct mlxsw_sp_nexthop *nh;
|
||||
u32 adj_hash_index = 0;
|
||||
u32 adj_index = 0;
|
||||
|
||||
mlxsw_sp_nexthop_for_each(nh, mlxsw_sp->router) {
|
||||
if (!mlxsw_sp_nexthop_offload(nh) ||
|
||||
mlxsw_sp_nexthop_group_has_ipip(nh))
|
||||
continue;
|
||||
|
||||
mlxsw_sp_nexthop_indexes(nh, &adj_index, &adj_hash_index);
|
||||
if (enable)
|
||||
mlxsw_sp_nexthop_counter_alloc(mlxsw_sp, nh);
|
||||
else
|
||||
mlxsw_sp_nexthop_counter_free(mlxsw_sp, nh);
|
||||
mlxsw_sp_nexthop_update(mlxsw_sp,
|
||||
adj_index + adj_hash_index, nh);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u64
|
||||
mlxsw_sp_dpipe_table_adj_size_get(void *priv)
|
||||
{
|
||||
struct mlxsw_sp *mlxsw_sp = priv;
|
||||
u64 size;
|
||||
|
||||
rtnl_lock();
|
||||
size = mlxsw_sp_dpipe_table_adj_size(mlxsw_sp);
|
||||
rtnl_unlock();
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static struct devlink_dpipe_table_ops mlxsw_sp_dpipe_table_adj_ops = {
|
||||
.matches_dump = mlxsw_sp_dpipe_table_adj_matches_dump,
|
||||
.actions_dump = mlxsw_sp_dpipe_table_adj_actions_dump,
|
||||
.entries_dump = mlxsw_sp_dpipe_table_adj_entries_dump,
|
||||
.counters_set_update = mlxsw_sp_dpipe_table_adj_counters_update,
|
||||
.size_get = mlxsw_sp_dpipe_table_adj_size_get,
|
||||
};
|
||||
|
||||
static int mlxsw_sp_dpipe_adj_table_init(struct mlxsw_sp *mlxsw_sp)
|
||||
{
|
||||
struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
|
||||
|
||||
return devlink_dpipe_table_register(devlink,
|
||||
MLXSW_SP_DPIPE_TABLE_NAME_ADJ,
|
||||
&mlxsw_sp_dpipe_table_adj_ops,
|
||||
mlxsw_sp, false);
|
||||
}
|
||||
|
||||
static void mlxsw_sp_dpipe_adj_table_fini(struct mlxsw_sp *mlxsw_sp)
|
||||
{
|
||||
struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
|
||||
|
||||
devlink_dpipe_table_unregister(devlink,
|
||||
MLXSW_SP_DPIPE_TABLE_NAME_ADJ);
|
||||
}
|
||||
|
||||
int mlxsw_sp_dpipe_init(struct mlxsw_sp *mlxsw_sp)
|
||||
{
|
||||
struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
|
||||
|
@ -846,8 +1214,14 @@ int mlxsw_sp_dpipe_init(struct mlxsw_sp *mlxsw_sp)
|
|||
err = mlxsw_sp_dpipe_host6_table_init(mlxsw_sp);
|
||||
if (err)
|
||||
goto err_host6_table_init;
|
||||
return 0;
|
||||
|
||||
err = mlxsw_sp_dpipe_adj_table_init(mlxsw_sp);
|
||||
if (err)
|
||||
goto err_adj_table_init;
|
||||
|
||||
return 0;
|
||||
err_adj_table_init:
|
||||
mlxsw_sp_dpipe_host6_table_fini(mlxsw_sp);
|
||||
err_host6_table_init:
|
||||
mlxsw_sp_dpipe_host4_table_fini(mlxsw_sp);
|
||||
err_host4_table_init:
|
||||
|
@ -861,6 +1235,7 @@ void mlxsw_sp_dpipe_fini(struct mlxsw_sp *mlxsw_sp)
|
|||
{
|
||||
struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
|
||||
|
||||
mlxsw_sp_dpipe_adj_table_fini(mlxsw_sp);
|
||||
mlxsw_sp_dpipe_host6_table_fini(mlxsw_sp);
|
||||
mlxsw_sp_dpipe_host4_table_fini(mlxsw_sp);
|
||||
mlxsw_sp_dpipe_erif_table_fini(mlxsw_sp);
|
||||
|
|
|
@ -56,5 +56,6 @@ static inline void mlxsw_sp_dpipe_fini(struct mlxsw_sp *mlxsw_sp)
|
|||
#define MLXSW_SP_DPIPE_TABLE_NAME_ERIF "mlxsw_erif"
|
||||
#define MLXSW_SP_DPIPE_TABLE_NAME_HOST4 "mlxsw_host4"
|
||||
#define MLXSW_SP_DPIPE_TABLE_NAME_HOST6 "mlxsw_host6"
|
||||
#define MLXSW_SP_DPIPE_TABLE_NAME_ADJ "mlxsw_adj"
|
||||
|
||||
#endif /* _MLXSW_PIPELINE_H_*/
|
||||
|
|
|
@ -78,6 +78,7 @@ struct mlxsw_sp_router {
|
|||
struct rhashtable neigh_ht;
|
||||
struct rhashtable nexthop_group_ht;
|
||||
struct rhashtable nexthop_ht;
|
||||
struct list_head nexthop_list;
|
||||
struct {
|
||||
struct mlxsw_sp_lpm_tree *trees;
|
||||
unsigned int tree_count;
|
||||
|
@ -1316,7 +1317,7 @@ mlxsw_sp_rif_neigh_next(struct mlxsw_sp_rif *rif,
|
|||
typeof(*neigh_entry),
|
||||
rif_list_node);
|
||||
}
|
||||
if (neigh_entry->rif_list_node.next == &rif->neigh_list)
|
||||
if (list_is_last(&neigh_entry->rif_list_node, &rif->neigh_list))
|
||||
return NULL;
|
||||
return list_next_entry(neigh_entry, rif_list_node);
|
||||
}
|
||||
|
@ -2028,6 +2029,7 @@ struct mlxsw_sp_nexthop_key {
|
|||
struct mlxsw_sp_nexthop {
|
||||
struct list_head neigh_list_node; /* member of neigh entry list */
|
||||
struct list_head rif_list_node;
|
||||
struct list_head router_list_node;
|
||||
struct mlxsw_sp_nexthop_group *nh_grp; /* pointer back to the group
|
||||
* this belongs to
|
||||
*/
|
||||
|
@ -2050,6 +2052,8 @@ struct mlxsw_sp_nexthop {
|
|||
struct mlxsw_sp_neigh_entry *neigh_entry;
|
||||
struct mlxsw_sp_ipip_entry *ipip_entry;
|
||||
};
|
||||
unsigned int counter_index;
|
||||
bool counter_valid;
|
||||
};
|
||||
|
||||
struct mlxsw_sp_nexthop_group {
|
||||
|
@ -2066,6 +2070,112 @@ struct mlxsw_sp_nexthop_group {
|
|||
#define nh_rif nexthops[0].rif
|
||||
};
|
||||
|
||||
void mlxsw_sp_nexthop_counter_alloc(struct mlxsw_sp *mlxsw_sp,
|
||||
struct mlxsw_sp_nexthop *nh)
|
||||
{
|
||||
struct devlink *devlink;
|
||||
|
||||
devlink = priv_to_devlink(mlxsw_sp->core);
|
||||
if (!devlink_dpipe_table_counter_enabled(devlink,
|
||||
MLXSW_SP_DPIPE_TABLE_NAME_ADJ))
|
||||
return;
|
||||
|
||||
if (mlxsw_sp_flow_counter_alloc(mlxsw_sp, &nh->counter_index))
|
||||
return;
|
||||
|
||||
nh->counter_valid = true;
|
||||
}
|
||||
|
||||
void mlxsw_sp_nexthop_counter_free(struct mlxsw_sp *mlxsw_sp,
|
||||
struct mlxsw_sp_nexthop *nh)
|
||||
{
|
||||
if (!nh->counter_valid)
|
||||
return;
|
||||
mlxsw_sp_flow_counter_free(mlxsw_sp, nh->counter_index);
|
||||
nh->counter_valid = false;
|
||||
}
|
||||
|
||||
int mlxsw_sp_nexthop_counter_get(struct mlxsw_sp *mlxsw_sp,
|
||||
struct mlxsw_sp_nexthop *nh, u64 *p_counter)
|
||||
{
|
||||
if (!nh->counter_valid)
|
||||
return -EINVAL;
|
||||
|
||||
return mlxsw_sp_flow_counter_get(mlxsw_sp, nh->counter_index,
|
||||
p_counter, NULL);
|
||||
}
|
||||
|
||||
struct mlxsw_sp_nexthop *mlxsw_sp_nexthop_next(struct mlxsw_sp_router *router,
|
||||
struct mlxsw_sp_nexthop *nh)
|
||||
{
|
||||
if (!nh) {
|
||||
if (list_empty(&router->nexthop_list))
|
||||
return NULL;
|
||||
else
|
||||
return list_first_entry(&router->nexthop_list,
|
||||
typeof(*nh), router_list_node);
|
||||
}
|
||||
if (list_is_last(&nh->router_list_node, &router->nexthop_list))
|
||||
return NULL;
|
||||
return list_next_entry(nh, router_list_node);
|
||||
}
|
||||
|
||||
bool mlxsw_sp_nexthop_offload(struct mlxsw_sp_nexthop *nh)
|
||||
{
|
||||
return nh->offloaded;
|
||||
}
|
||||
|
||||
unsigned char *mlxsw_sp_nexthop_ha(struct mlxsw_sp_nexthop *nh)
|
||||
{
|
||||
if (!nh->offloaded)
|
||||
return NULL;
|
||||
return nh->neigh_entry->ha;
|
||||
}
|
||||
|
||||
int mlxsw_sp_nexthop_indexes(struct mlxsw_sp_nexthop *nh, u32 *p_adj_index,
|
||||
u32 *p_adj_hash_index)
|
||||
{
|
||||
struct mlxsw_sp_nexthop_group *nh_grp = nh->nh_grp;
|
||||
u32 adj_hash_index = 0;
|
||||
int i;
|
||||
|
||||
if (!nh->offloaded || !nh_grp->adj_index_valid)
|
||||
return -EINVAL;
|
||||
|
||||
*p_adj_index = nh_grp->adj_index;
|
||||
|
||||
for (i = 0; i < nh_grp->count; i++) {
|
||||
struct mlxsw_sp_nexthop *nh_iter = &nh_grp->nexthops[i];
|
||||
|
||||
if (nh_iter == nh)
|
||||
break;
|
||||
if (nh_iter->offloaded)
|
||||
adj_hash_index++;
|
||||
}
|
||||
|
||||
*p_adj_hash_index = adj_hash_index;
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct mlxsw_sp_rif *mlxsw_sp_nexthop_rif(struct mlxsw_sp_nexthop *nh)
|
||||
{
|
||||
return nh->rif;
|
||||
}
|
||||
|
||||
bool mlxsw_sp_nexthop_group_has_ipip(struct mlxsw_sp_nexthop *nh)
|
||||
{
|
||||
struct mlxsw_sp_nexthop_group *nh_grp = nh->nh_grp;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < nh_grp->count; i++) {
|
||||
struct mlxsw_sp_nexthop *nh_iter = &nh_grp->nexthops[i];
|
||||
|
||||
if (nh_iter->type == MLXSW_SP_NEXTHOP_TYPE_IPIP)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static struct fib_info *
|
||||
mlxsw_sp_nexthop4_group_fi(const struct mlxsw_sp_nexthop_group *nh_grp)
|
||||
{
|
||||
|
@ -2323,8 +2433,8 @@ static int mlxsw_sp_adj_index_mass_update(struct mlxsw_sp *mlxsw_sp,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int mlxsw_sp_nexthop_mac_update(struct mlxsw_sp *mlxsw_sp, u32 adj_index,
|
||||
struct mlxsw_sp_nexthop *nh)
|
||||
int mlxsw_sp_nexthop_update(struct mlxsw_sp *mlxsw_sp, u32 adj_index,
|
||||
struct mlxsw_sp_nexthop *nh)
|
||||
{
|
||||
struct mlxsw_sp_neigh_entry *neigh_entry = nh->neigh_entry;
|
||||
char ratr_pl[MLXSW_REG_RATR_LEN];
|
||||
|
@ -2333,6 +2443,11 @@ static int mlxsw_sp_nexthop_mac_update(struct mlxsw_sp *mlxsw_sp, u32 adj_index,
|
|||
true, MLXSW_REG_RATR_TYPE_ETHERNET,
|
||||
adj_index, neigh_entry->rif);
|
||||
mlxsw_reg_ratr_eth_entry_pack(ratr_pl, neigh_entry->ha);
|
||||
if (nh->counter_valid)
|
||||
mlxsw_reg_ratr_counter_pack(ratr_pl, nh->counter_index, true);
|
||||
else
|
||||
mlxsw_reg_ratr_counter_pack(ratr_pl, 0, false);
|
||||
|
||||
return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ratr), ratr_pl);
|
||||
}
|
||||
|
||||
|
@ -2367,7 +2482,7 @@ mlxsw_sp_nexthop_group_update(struct mlxsw_sp *mlxsw_sp,
|
|||
if (nh->update || reallocate) {
|
||||
switch (nh->type) {
|
||||
case MLXSW_SP_NEXTHOP_TYPE_ETH:
|
||||
err = mlxsw_sp_nexthop_mac_update
|
||||
err = mlxsw_sp_nexthop_update
|
||||
(mlxsw_sp, adj_index, nh);
|
||||
break;
|
||||
case MLXSW_SP_NEXTHOP_TYPE_IPIP:
|
||||
|
@ -2784,6 +2899,9 @@ static int mlxsw_sp_nexthop4_init(struct mlxsw_sp *mlxsw_sp,
|
|||
if (err)
|
||||
return err;
|
||||
|
||||
mlxsw_sp_nexthop_counter_alloc(mlxsw_sp, nh);
|
||||
list_add_tail(&nh->router_list_node, &mlxsw_sp->router->nexthop_list);
|
||||
|
||||
if (!dev)
|
||||
return 0;
|
||||
|
||||
|
@ -2807,6 +2925,8 @@ static void mlxsw_sp_nexthop4_fini(struct mlxsw_sp *mlxsw_sp,
|
|||
struct mlxsw_sp_nexthop *nh)
|
||||
{
|
||||
mlxsw_sp_nexthop4_type_fini(mlxsw_sp, nh);
|
||||
list_del(&nh->router_list_node);
|
||||
mlxsw_sp_nexthop_counter_free(mlxsw_sp, nh);
|
||||
mlxsw_sp_nexthop_remove(mlxsw_sp, nh);
|
||||
}
|
||||
|
||||
|
@ -4044,6 +4164,9 @@ static int mlxsw_sp_nexthop6_init(struct mlxsw_sp *mlxsw_sp,
|
|||
|
||||
nh->nh_grp = nh_grp;
|
||||
memcpy(&nh->gw_addr, &rt->rt6i_gateway, sizeof(nh->gw_addr));
|
||||
mlxsw_sp_nexthop_counter_alloc(mlxsw_sp, nh);
|
||||
|
||||
list_add_tail(&nh->router_list_node, &mlxsw_sp->router->nexthop_list);
|
||||
|
||||
if (!dev)
|
||||
return 0;
|
||||
|
@ -4056,6 +4179,8 @@ static void mlxsw_sp_nexthop6_fini(struct mlxsw_sp *mlxsw_sp,
|
|||
struct mlxsw_sp_nexthop *nh)
|
||||
{
|
||||
mlxsw_sp_nexthop6_type_fini(mlxsw_sp, nh);
|
||||
list_del(&nh->router_list_node);
|
||||
mlxsw_sp_nexthop_counter_free(mlxsw_sp, nh);
|
||||
}
|
||||
|
||||
static bool mlxsw_sp_rt6_is_gateway(const struct mlxsw_sp *mlxsw_sp,
|
||||
|
@ -5990,6 +6115,7 @@ int mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp)
|
|||
if (err)
|
||||
goto err_nexthop_group_ht_init;
|
||||
|
||||
INIT_LIST_HEAD(&mlxsw_sp->router->nexthop_list);
|
||||
err = mlxsw_sp_lpm_init(mlxsw_sp);
|
||||
if (err)
|
||||
goto err_lpm_init;
|
||||
|
|
|
@ -62,6 +62,7 @@ enum mlxsw_sp_rif_counter_dir {
|
|||
};
|
||||
|
||||
struct mlxsw_sp_neigh_entry;
|
||||
struct mlxsw_sp_nexthop;
|
||||
|
||||
struct mlxsw_sp_rif *mlxsw_sp_rif_by_index(const struct mlxsw_sp *mlxsw_sp,
|
||||
u16 rif_index);
|
||||
|
@ -108,5 +109,24 @@ union mlxsw_sp_l3addr
|
|||
mlxsw_sp_ipip_netdev_daddr(enum mlxsw_sp_l3proto proto,
|
||||
const struct net_device *ol_dev);
|
||||
__be32 mlxsw_sp_ipip_netdev_daddr4(const struct net_device *ol_dev);
|
||||
struct mlxsw_sp_nexthop *mlxsw_sp_nexthop_next(struct mlxsw_sp_router *router,
|
||||
struct mlxsw_sp_nexthop *nh);
|
||||
bool mlxsw_sp_nexthop_offload(struct mlxsw_sp_nexthop *nh);
|
||||
unsigned char *mlxsw_sp_nexthop_ha(struct mlxsw_sp_nexthop *nh);
|
||||
int mlxsw_sp_nexthop_indexes(struct mlxsw_sp_nexthop *nh, u32 *p_adj_index,
|
||||
u32 *p_adj_hash_index);
|
||||
struct mlxsw_sp_rif *mlxsw_sp_nexthop_rif(struct mlxsw_sp_nexthop *nh);
|
||||
bool mlxsw_sp_nexthop_group_has_ipip(struct mlxsw_sp_nexthop *nh);
|
||||
#define mlxsw_sp_nexthop_for_each(nh, router) \
|
||||
for (nh = mlxsw_sp_nexthop_next(router, NULL); nh; \
|
||||
nh = mlxsw_sp_nexthop_next(router, nh))
|
||||
int mlxsw_sp_nexthop_counter_get(struct mlxsw_sp *mlxsw_sp,
|
||||
struct mlxsw_sp_nexthop *nh, u64 *p_counter);
|
||||
int mlxsw_sp_nexthop_update(struct mlxsw_sp *mlxsw_sp, u32 adj_index,
|
||||
struct mlxsw_sp_nexthop *nh);
|
||||
void mlxsw_sp_nexthop_counter_alloc(struct mlxsw_sp *mlxsw_sp,
|
||||
struct mlxsw_sp_nexthop *nh);
|
||||
void mlxsw_sp_nexthop_counter_free(struct mlxsw_sp *mlxsw_sp,
|
||||
struct mlxsw_sp_nexthop *nh);
|
||||
|
||||
#endif /* _MLXSW_ROUTER_H_*/
|
||||
|
|
Loading…
Reference in a new issue