2018-08-09 11:59:11 +03:00
// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
/* Copyright (c) 2017-2018 Mellanox Technologies. All rights reserved */
2017-03-28 17:24:12 +02:00
# include <linux/kernel.h>
# include <net/devlink.h>
# include "spectrum.h"
# include "spectrum_dpipe.h"
2017-03-28 17:24:17 +02:00
# include "spectrum_router.h"
2017-03-28 17:24:12 +02:00
2017-03-28 17:24:13 +02:00
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 ,
2017-09-25 10:32:22 +02:00
MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_INDEX ,
2017-10-22 23:11:43 +02:00
MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_SIZE ,
2017-09-25 10:32:22 +02:00
MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_HASH_INDEX ,
2017-03-28 17:24:13 +02:00
} ;
static struct devlink_dpipe_field mlxsw_sp_dpipe_fields_metadata [ ] = {
2017-09-25 10:32:21 +02:00
{
. name = " erif_port " ,
. id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT ,
. bitwidth = 32 ,
. mapping_type = DEVLINK_DPIPE_FIELD_MAPPING_TYPE_IFINDEX ,
2017-03-28 17:24:13 +02:00
} ,
2017-09-25 10:32:21 +02:00
{
. name = " l3_forward " ,
. id = MLXSW_SP_DPIPE_FIELD_METADATA_L3_FORWARD ,
. bitwidth = 1 ,
2017-03-28 17:24:13 +02:00
} ,
2017-09-25 10:32:21 +02:00
{
. name = " l3_drop " ,
. id = MLXSW_SP_DPIPE_FIELD_METADATA_L3_DROP ,
. bitwidth = 1 ,
2017-03-28 17:24:13 +02:00
} ,
2017-09-25 10:32:22 +02:00
{
. name = " adj_index " ,
. id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_INDEX ,
. bitwidth = 32 ,
} ,
2017-10-22 23:11:43 +02:00
{
. name = " adj_size " ,
. id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_SIZE ,
. bitwidth = 32 ,
} ,
2017-09-25 10:32:22 +02:00
{
. name = " adj_hash_index " ,
. id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_HASH_INDEX ,
. bitwidth = 32 ,
} ,
2017-03-28 17:24:13 +02:00
} ;
enum mlxsw_sp_dpipe_header_id {
MLXSW_SP_DPIPE_HEADER_METADATA ,
} ;
static struct devlink_dpipe_header mlxsw_sp_dpipe_header_metadata = {
. name = " mlxsw_meta " ,
. id = MLXSW_SP_DPIPE_HEADER_METADATA ,
. fields = mlxsw_sp_dpipe_fields_metadata ,
. fields_count = ARRAY_SIZE ( mlxsw_sp_dpipe_fields_metadata ) ,
} ;
static struct devlink_dpipe_header * mlxsw_dpipe_headers [ ] = {
& mlxsw_sp_dpipe_header_metadata ,
2017-08-24 08:40:06 +02:00
& devlink_dpipe_header_ethernet ,
& devlink_dpipe_header_ipv4 ,
2017-08-31 17:59:14 +02:00
& devlink_dpipe_header_ipv6 ,
2017-03-28 17:24:13 +02:00
} ;
2017-03-28 17:24:12 +02:00
static struct devlink_dpipe_headers mlxsw_sp_dpipe_headers = {
. headers = mlxsw_dpipe_headers ,
. headers_count = ARRAY_SIZE ( mlxsw_dpipe_headers ) ,
} ;
2017-03-28 17:24:13 +02:00
static int mlxsw_sp_dpipe_table_erif_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 = & mlxsw_sp_dpipe_header_metadata ;
action . field_id = MLXSW_SP_DPIPE_FIELD_METADATA_L3_FORWARD ;
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_L3_DROP ;
return devlink_dpipe_action_put ( skb , & action ) ;
}
static int mlxsw_sp_dpipe_table_erif_matches_dump ( void * priv ,
struct sk_buff * skb )
{
struct devlink_dpipe_match match = { 0 } ;
match . type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT ;
match . header = & mlxsw_sp_dpipe_header_metadata ;
match . field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT ;
return devlink_dpipe_match_put ( skb , & match ) ;
}
2017-03-28 17:24:17 +02:00
static void
mlxsw_sp_erif_match_action_prepare ( struct devlink_dpipe_match * match ,
struct devlink_dpipe_action * action )
{
action - > type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY ;
action - > header = & mlxsw_sp_dpipe_header_metadata ;
action - > field_id = MLXSW_SP_DPIPE_FIELD_METADATA_L3_FORWARD ;
match - > type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT ;
match - > header = & mlxsw_sp_dpipe_header_metadata ;
match - > field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT ;
}
static int mlxsw_sp_erif_entry_prepare ( struct devlink_dpipe_entry * entry ,
struct devlink_dpipe_value * match_value ,
struct devlink_dpipe_match * match ,
struct devlink_dpipe_value * action_value ,
struct devlink_dpipe_action * action )
{
entry - > match_values = match_value ;
entry - > match_values_count = 1 ;
entry - > action_values = action_value ;
entry - > action_values_count = 1 ;
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_value - > action = action ;
action_value - > value_size = sizeof ( u32 ) ;
action_value - > value = kmalloc ( action_value - > value_size , GFP_KERNEL ) ;
if ( ! action_value - > value )
goto err_action_alloc ;
return 0 ;
err_action_alloc :
kfree ( match_value - > value ) ;
return - ENOMEM ;
}
static int mlxsw_sp_erif_entry_get ( struct mlxsw_sp * mlxsw_sp ,
struct devlink_dpipe_entry * entry ,
struct mlxsw_sp_rif * rif ,
bool counters_enabled )
{
u32 * action_value ;
u32 * rif_value ;
u64 cnt ;
int err ;
/* Set Match RIF index */
rif_value = entry - > match_values - > value ;
* rif_value = mlxsw_sp_rif_index ( rif ) ;
entry - > match_values - > mapping_value = mlxsw_sp_rif_dev_ifindex ( rif ) ;
entry - > match_values - > mapping_valid = true ;
/* Set Action Forwarding */
action_value = entry - > action_values - > value ;
* action_value = 1 ;
entry - > counter_valid = false ;
entry - > counter = 0 ;
2017-05-18 09:18:52 +02:00
entry - > index = mlxsw_sp_rif_index ( rif ) ;
2017-03-28 17:24:17 +02:00
if ( ! counters_enabled )
return 0 ;
err = mlxsw_sp_rif_counter_value_get ( mlxsw_sp , rif ,
MLXSW_SP_RIF_COUNTER_EGRESS ,
& cnt ) ;
if ( ! err ) {
entry - > counter = cnt ;
entry - > counter_valid = true ;
}
return 0 ;
}
static int
2017-08-24 08:40:01 +02:00
mlxsw_sp_dpipe_table_erif_entries_dump ( void * priv , bool counters_enabled ,
struct devlink_dpipe_dump_ctx * dump_ctx )
2017-03-28 17:24:17 +02:00
{
2017-05-18 09:22:45 +02:00
struct devlink_dpipe_value match_value , action_value ;
2017-03-28 17:24:17 +02:00
struct devlink_dpipe_action action = { 0 } ;
struct devlink_dpipe_match match = { 0 } ;
struct devlink_dpipe_entry entry = { 0 } ;
struct mlxsw_sp * mlxsw_sp = priv ;
unsigned int rif_count ;
int i , j ;
int err ;
2017-05-18 09:22:45 +02:00
memset ( & match_value , 0 , sizeof ( match_value ) ) ;
memset ( & action_value , 0 , sizeof ( action_value ) ) ;
2017-03-28 17:24:17 +02:00
mlxsw_sp_erif_match_action_prepare ( & match , & action ) ;
err = mlxsw_sp_erif_entry_prepare ( & entry , & match_value , & match ,
& action_value , & action ) ;
if ( err )
return err ;
rif_count = MLXSW_CORE_RES_GET ( mlxsw_sp - > core , MAX_RIFS ) ;
rtnl_lock ( ) ;
i = 0 ;
start_again :
err = devlink_dpipe_entry_ctx_prepare ( dump_ctx ) ;
if ( err )
return err ;
j = 0 ;
for ( ; i < rif_count ; i + + ) {
2017-05-16 19:38:27 +02:00
struct mlxsw_sp_rif * rif = mlxsw_sp_rif_by_index ( mlxsw_sp , i ) ;
2019-01-20 06:50:49 +00:00
if ( ! rif | | ! mlxsw_sp_rif_dev ( rif ) )
2017-03-28 17:24:17 +02:00
continue ;
2017-05-16 19:38:27 +02:00
err = mlxsw_sp_erif_entry_get ( mlxsw_sp , & entry , rif ,
2017-03-28 17:24:17 +02:00
counters_enabled ) ;
if ( err )
goto err_entry_get ;
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 ;
}
j + + ;
}
devlink_dpipe_entry_ctx_close ( dump_ctx ) ;
if ( i ! = rif_count )
goto start_again ;
rtnl_unlock ( ) ;
2017-08-24 08:40:03 +02:00
devlink_dpipe_entry_clear ( & entry ) ;
2017-03-28 17:24:17 +02:00
return 0 ;
err_entry_append :
err_entry_get :
rtnl_unlock ( ) ;
2017-08-24 08:40:03 +02:00
devlink_dpipe_entry_clear ( & entry ) ;
2017-03-28 17:24:17 +02:00
return err ;
}
2017-08-24 08:40:01 +02:00
static int mlxsw_sp_dpipe_table_erif_counters_update ( void * priv , bool enable )
2017-03-28 17:24:17 +02:00
{
struct mlxsw_sp * mlxsw_sp = priv ;
int i ;
rtnl_lock ( ) ;
for ( i = 0 ; i < MLXSW_CORE_RES_GET ( mlxsw_sp - > core , MAX_RIFS ) ; i + + ) {
2017-05-16 19:38:27 +02:00
struct mlxsw_sp_rif * rif = mlxsw_sp_rif_by_index ( mlxsw_sp , i ) ;
if ( ! rif )
2017-03-28 17:24:17 +02:00
continue ;
if ( enable )
2017-05-16 19:38:27 +02:00
mlxsw_sp_rif_counter_alloc ( mlxsw_sp , rif ,
2017-03-28 17:24:17 +02:00
MLXSW_SP_RIF_COUNTER_EGRESS ) ;
else
2017-05-16 19:38:27 +02:00
mlxsw_sp_rif_counter_free ( mlxsw_sp , rif ,
2017-03-28 17:24:17 +02:00
MLXSW_SP_RIF_COUNTER_EGRESS ) ;
}
rtnl_unlock ( ) ;
return 0 ;
}
2017-08-24 08:40:02 +02:00
static u64 mlxsw_sp_dpipe_table_erif_size_get ( void * priv )
{
struct mlxsw_sp * mlxsw_sp = priv ;
return MLXSW_CORE_RES_GET ( mlxsw_sp - > core , MAX_RIFS ) ;
}
2017-03-28 17:24:13 +02:00
static struct devlink_dpipe_table_ops mlxsw_sp_erif_ops = {
. matches_dump = mlxsw_sp_dpipe_table_erif_matches_dump ,
. actions_dump = mlxsw_sp_dpipe_table_erif_actions_dump ,
2017-08-24 08:40:01 +02:00
. entries_dump = mlxsw_sp_dpipe_table_erif_entries_dump ,
. counters_set_update = mlxsw_sp_dpipe_table_erif_counters_update ,
2017-08-24 08:40:02 +02:00
. size_get = mlxsw_sp_dpipe_table_erif_size_get ,
2017-03-28 17:24:13 +02:00
} ;
static int mlxsw_sp_dpipe_erif_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_ERIF ,
& mlxsw_sp_erif_ops ,
2017-08-24 08:40:02 +02:00
mlxsw_sp , false ) ;
2017-03-28 17:24:13 +02:00
}
static void mlxsw_sp_dpipe_erif_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_ERIF ) ;
}
2017-08-24 08:40:06 +02:00
static int mlxsw_sp_dpipe_table_host_matches_dump ( struct sk_buff * skb , int type )
{
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_ERIF_PORT ;
err = devlink_dpipe_match_put ( skb , & match ) ;
if ( err )
return err ;
2017-08-31 17:59:14 +02:00
switch ( type ) {
case AF_INET :
match . type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT ;
match . header = & devlink_dpipe_header_ipv4 ;
match . field_id = DEVLINK_DPIPE_FIELD_IPV4_DST_IP ;
break ;
case AF_INET6 :
match . type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT ;
match . header = & devlink_dpipe_header_ipv6 ;
match . field_id = DEVLINK_DPIPE_FIELD_IPV6_DST_IP ;
break ;
default :
WARN_ON ( 1 ) ;
return - EINVAL ;
}
2017-08-24 08:40:06 +02:00
return devlink_dpipe_match_put ( skb , & match ) ;
}
static int
mlxsw_sp_dpipe_table_host4_matches_dump ( void * priv , struct sk_buff * skb )
{
return mlxsw_sp_dpipe_table_host_matches_dump ( skb , AF_INET ) ;
}
static int
2017-08-31 17:59:14 +02:00
mlxsw_sp_dpipe_table_host_actions_dump ( void * priv , struct sk_buff * skb )
2017-08-24 08:40:06 +02:00
{
struct devlink_dpipe_action action = { 0 } ;
action . type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY ;
action . header = & devlink_dpipe_header_ethernet ;
action . field_id = DEVLINK_DPIPE_FIELD_ETHERNET_DST_MAC ;
return devlink_dpipe_action_put ( skb , & action ) ;
}
2017-08-24 08:40:09 +02:00
enum mlxsw_sp_dpipe_table_host_match {
MLXSW_SP_DPIPE_TABLE_HOST_MATCH_RIF ,
MLXSW_SP_DPIPE_TABLE_HOST_MATCH_DIP ,
MLXSW_SP_DPIPE_TABLE_HOST_MATCH_COUNT ,
} ;
static void
mlxsw_sp_dpipe_table_host_match_action_prepare ( struct devlink_dpipe_match * matches ,
struct devlink_dpipe_action * action ,
int type )
{
struct devlink_dpipe_match * match ;
match = & matches [ MLXSW_SP_DPIPE_TABLE_HOST_MATCH_RIF ] ;
match - > type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT ;
match - > header = & mlxsw_sp_dpipe_header_metadata ;
match - > field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT ;
match = & matches [ MLXSW_SP_DPIPE_TABLE_HOST_MATCH_DIP ] ;
match - > type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT ;
2017-08-31 17:59:17 +02:00
switch ( type ) {
case AF_INET :
match - > header = & devlink_dpipe_header_ipv4 ;
match - > field_id = DEVLINK_DPIPE_FIELD_IPV4_DST_IP ;
break ;
case AF_INET6 :
match - > header = & devlink_dpipe_header_ipv6 ;
match - > field_id = DEVLINK_DPIPE_FIELD_IPV6_DST_IP ;
break ;
default :
WARN_ON ( 1 ) ;
return ;
}
2017-08-24 08:40:09 +02:00
action - > type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY ;
action - > header = & devlink_dpipe_header_ethernet ;
action - > field_id = DEVLINK_DPIPE_FIELD_ETHERNET_DST_MAC ;
}
static int
mlxsw_sp_dpipe_table_host_entry_prepare ( struct devlink_dpipe_entry * entry ,
struct devlink_dpipe_value * match_values ,
struct devlink_dpipe_match * matches ,
struct devlink_dpipe_value * action_value ,
struct devlink_dpipe_action * action ,
int type )
{
struct devlink_dpipe_value * match_value ;
struct devlink_dpipe_match * match ;
entry - > match_values = match_values ;
entry - > match_values_count = MLXSW_SP_DPIPE_TABLE_HOST_MATCH_COUNT ;
entry - > action_values = action_value ;
entry - > action_values_count = 1 ;
match = & matches [ MLXSW_SP_DPIPE_TABLE_HOST_MATCH_RIF ] ;
match_value = & match_values [ MLXSW_SP_DPIPE_TABLE_HOST_MATCH_RIF ] ;
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_HOST_MATCH_DIP ] ;
match_value = & match_values [ MLXSW_SP_DPIPE_TABLE_HOST_MATCH_DIP ] ;
match_value - > match = match ;
2017-08-31 17:59:17 +02:00
switch ( type ) {
case AF_INET :
match_value - > value_size = sizeof ( u32 ) ;
break ;
case AF_INET6 :
match_value - > value_size = sizeof ( struct in6_addr ) ;
break ;
default :
WARN_ON ( 1 ) ;
return - EINVAL ;
}
2017-08-24 08:40:09 +02:00
match_value - > value = kmalloc ( match_value - > value_size , GFP_KERNEL ) ;
if ( ! match_value - > value )
return - ENOMEM ;
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 ;
return 0 ;
}
static void
2017-08-31 17:59:16 +02:00
__mlxsw_sp_dpipe_table_host_entry_fill ( struct devlink_dpipe_entry * entry ,
struct mlxsw_sp_rif * rif ,
unsigned char * ha , void * dip )
2017-08-24 08:40:09 +02:00
{
struct devlink_dpipe_value * value ;
u32 * rif_value ;
u8 * ha_value ;
/* Set Match RIF index */
value = & entry - > match_values [ MLXSW_SP_DPIPE_TABLE_HOST_MATCH_RIF ] ;
rif_value = value - > value ;
* rif_value = mlxsw_sp_rif_index ( rif ) ;
value - > mapping_value = mlxsw_sp_rif_dev_ifindex ( rif ) ;
value - > mapping_valid = true ;
/* Set Match DIP */
value = & entry - > match_values [ MLXSW_SP_DPIPE_TABLE_HOST_MATCH_DIP ] ;
2017-08-31 17:59:16 +02:00
memcpy ( value - > value , dip , value - > value_size ) ;
2017-08-24 08:40:09 +02:00
/* Set Action DMAC */
value = entry - > action_values ;
ha_value = value - > value ;
ether_addr_copy ( ha_value , ha ) ;
}
static void
mlxsw_sp_dpipe_table_host4_entry_fill ( struct devlink_dpipe_entry * entry ,
struct mlxsw_sp_neigh_entry * neigh_entry ,
struct mlxsw_sp_rif * rif )
{
unsigned char * ha ;
u32 dip ;
ha = mlxsw_sp_neigh_entry_ha ( neigh_entry ) ;
dip = mlxsw_sp_neigh4_entry_dip ( neigh_entry ) ;
2017-08-31 17:59:16 +02:00
__mlxsw_sp_dpipe_table_host_entry_fill ( entry , rif , ha , & dip ) ;
2017-08-24 08:40:09 +02:00
}
2017-08-31 17:59:17 +02:00
static void
mlxsw_sp_dpipe_table_host6_entry_fill ( struct devlink_dpipe_entry * entry ,
struct mlxsw_sp_neigh_entry * neigh_entry ,
struct mlxsw_sp_rif * rif )
{
struct in6_addr * dip ;
unsigned char * ha ;
ha = mlxsw_sp_neigh_entry_ha ( neigh_entry ) ;
dip = mlxsw_sp_neigh6_entry_dip ( neigh_entry ) ;
__mlxsw_sp_dpipe_table_host_entry_fill ( entry , rif , ha , dip ) ;
}
2017-08-24 08:40:09 +02:00
static void
mlxsw_sp_dpipe_table_host_entry_fill ( struct mlxsw_sp * mlxsw_sp ,
struct devlink_dpipe_entry * entry ,
struct mlxsw_sp_neigh_entry * neigh_entry ,
struct mlxsw_sp_rif * rif ,
int type )
{
int err ;
2017-08-31 17:59:17 +02:00
switch ( type ) {
case AF_INET :
mlxsw_sp_dpipe_table_host4_entry_fill ( entry , neigh_entry , rif ) ;
break ;
case AF_INET6 :
mlxsw_sp_dpipe_table_host6_entry_fill ( entry , neigh_entry , rif ) ;
break ;
default :
WARN_ON ( 1 ) ;
return ;
}
2017-08-24 08:40:09 +02:00
err = mlxsw_sp_neigh_counter_get ( mlxsw_sp , neigh_entry ,
& entry - > counter ) ;
if ( ! err )
entry - > counter_valid = true ;
}
static int
mlxsw_sp_dpipe_table_host_entries_get ( struct mlxsw_sp * mlxsw_sp ,
struct devlink_dpipe_entry * entry ,
bool counters_enabled ,
struct devlink_dpipe_dump_ctx * dump_ctx ,
int type )
{
int rif_neigh_count = 0 ;
int rif_neigh_skip = 0 ;
int neigh_count = 0 ;
int rif_count ;
int i , j ;
int err ;
rtnl_lock ( ) ;
i = 0 ;
rif_count = MLXSW_CORE_RES_GET ( mlxsw_sp - > core , MAX_RIFS ) ;
start_again :
err = devlink_dpipe_entry_ctx_prepare ( dump_ctx ) ;
if ( err )
goto err_ctx_prepare ;
j = 0 ;
rif_neigh_skip = rif_neigh_count ;
for ( ; i < MLXSW_CORE_RES_GET ( mlxsw_sp - > core , MAX_RIFS ) ; i + + ) {
struct mlxsw_sp_rif * rif = mlxsw_sp_rif_by_index ( mlxsw_sp , i ) ;
struct mlxsw_sp_neigh_entry * neigh_entry ;
if ( ! rif )
continue ;
rif_neigh_count = 0 ;
mlxsw_sp_rif_neigh_for_each ( neigh_entry , rif ) {
2017-08-31 17:59:17 +02:00
int neigh_type = mlxsw_sp_neigh_entry_type ( neigh_entry ) ;
if ( neigh_type ! = type )
continue ;
if ( neigh_type = = AF_INET6 & &
mlxsw_sp_neigh_ipv6_ignore ( neigh_entry ) )
2017-08-26 08:35:39 +02:00
continue ;
2017-08-24 08:40:09 +02:00
if ( rif_neigh_count < rif_neigh_skip )
goto skip ;
mlxsw_sp_dpipe_table_host_entry_fill ( mlxsw_sp , entry ,
neigh_entry , rif ,
type ) ;
entry - > index = neigh_count ;
err = devlink_dpipe_entry_ctx_append ( dump_ctx , entry ) ;
if ( err ) {
if ( err = = - EMSGSIZE ) {
if ( ! j )
goto err_entry_append ;
else
goto out ;
}
goto err_entry_append ;
}
neigh_count + + ;
j + + ;
skip :
rif_neigh_count + + ;
}
rif_neigh_skip = 0 ;
}
out :
devlink_dpipe_entry_ctx_close ( dump_ctx ) ;
if ( i ! = rif_count )
goto start_again ;
rtnl_unlock ( ) ;
return 0 ;
err_ctx_prepare :
err_entry_append :
rtnl_unlock ( ) ;
return err ;
}
static int
mlxsw_sp_dpipe_table_host_entries_dump ( struct mlxsw_sp * mlxsw_sp ,
bool counters_enabled ,
struct devlink_dpipe_dump_ctx * dump_ctx ,
int type )
{
struct devlink_dpipe_value match_values [ MLXSW_SP_DPIPE_TABLE_HOST_MATCH_COUNT ] ;
struct devlink_dpipe_match matches [ MLXSW_SP_DPIPE_TABLE_HOST_MATCH_COUNT ] ;
struct devlink_dpipe_value action_value ;
struct devlink_dpipe_action action = { 0 } ;
struct devlink_dpipe_entry entry = { 0 } ;
int err ;
memset ( matches , 0 , MLXSW_SP_DPIPE_TABLE_HOST_MATCH_COUNT *
sizeof ( matches [ 0 ] ) ) ;
memset ( match_values , 0 , MLXSW_SP_DPIPE_TABLE_HOST_MATCH_COUNT *
sizeof ( match_values [ 0 ] ) ) ;
memset ( & action_value , 0 , sizeof ( action_value ) ) ;
mlxsw_sp_dpipe_table_host_match_action_prepare ( matches , & action , type ) ;
err = mlxsw_sp_dpipe_table_host_entry_prepare ( & entry , match_values ,
matches , & action_value ,
& action , type ) ;
if ( err )
goto out ;
err = mlxsw_sp_dpipe_table_host_entries_get ( mlxsw_sp , & entry ,
counters_enabled , dump_ctx ,
type ) ;
out :
devlink_dpipe_entry_clear ( & entry ) ;
return err ;
}
static int
mlxsw_sp_dpipe_table_host4_entries_dump ( void * priv , bool counters_enabled ,
struct devlink_dpipe_dump_ctx * dump_ctx )
{
struct mlxsw_sp * mlxsw_sp = priv ;
return mlxsw_sp_dpipe_table_host_entries_dump ( mlxsw_sp ,
counters_enabled ,
dump_ctx , AF_INET ) ;
}
2017-08-24 08:40:10 +02:00
static void
mlxsw_sp_dpipe_table_host_counters_update ( struct mlxsw_sp * mlxsw_sp ,
bool enable , int type )
{
int i ;
rtnl_lock ( ) ;
for ( i = 0 ; i < MLXSW_CORE_RES_GET ( mlxsw_sp - > core , MAX_RIFS ) ; i + + ) {
struct mlxsw_sp_rif * rif = mlxsw_sp_rif_by_index ( mlxsw_sp , i ) ;
struct mlxsw_sp_neigh_entry * neigh_entry ;
if ( ! rif )
continue ;
mlxsw_sp_rif_neigh_for_each ( neigh_entry , rif ) {
2017-08-31 17:59:19 +02:00
int neigh_type = mlxsw_sp_neigh_entry_type ( neigh_entry ) ;
if ( neigh_type ! = type )
continue ;
if ( neigh_type = = AF_INET6 & &
mlxsw_sp_neigh_ipv6_ignore ( neigh_entry ) )
2017-08-24 08:40:10 +02:00
continue ;
2017-08-31 17:59:19 +02:00
2017-08-24 08:40:10 +02:00
mlxsw_sp_neigh_entry_counter_update ( mlxsw_sp ,
neigh_entry ,
enable ) ;
}
}
rtnl_unlock ( ) ;
}
static int mlxsw_sp_dpipe_table_host4_counters_update ( void * priv , bool enable )
{
struct mlxsw_sp * mlxsw_sp = priv ;
mlxsw_sp_dpipe_table_host_counters_update ( mlxsw_sp , enable , AF_INET ) ;
return 0 ;
}
2017-08-24 08:40:06 +02:00
static u64
mlxsw_sp_dpipe_table_host_size_get ( struct mlxsw_sp * mlxsw_sp , int type )
{
u64 size = 0 ;
int i ;
rtnl_lock ( ) ;
for ( i = 0 ; i < MLXSW_CORE_RES_GET ( mlxsw_sp - > core , MAX_RIFS ) ; i + + ) {
struct mlxsw_sp_rif * rif = mlxsw_sp_rif_by_index ( mlxsw_sp , i ) ;
struct mlxsw_sp_neigh_entry * neigh_entry ;
if ( ! rif )
continue ;
mlxsw_sp_rif_neigh_for_each ( neigh_entry , rif ) {
2017-08-31 17:59:14 +02:00
int neigh_type = mlxsw_sp_neigh_entry_type ( neigh_entry ) ;
if ( neigh_type ! = type )
2017-08-24 08:40:06 +02:00
continue ;
2017-08-31 17:59:14 +02:00
if ( neigh_type = = AF_INET6 & &
mlxsw_sp_neigh_ipv6_ignore ( neigh_entry ) )
continue ;
2017-08-24 08:40:06 +02:00
size + + ;
}
}
rtnl_unlock ( ) ;
return size ;
}
static u64 mlxsw_sp_dpipe_table_host4_size_get ( void * priv )
{
struct mlxsw_sp * mlxsw_sp = priv ;
return mlxsw_sp_dpipe_table_host_size_get ( mlxsw_sp , AF_INET ) ;
}
static struct devlink_dpipe_table_ops mlxsw_sp_host4_ops = {
. matches_dump = mlxsw_sp_dpipe_table_host4_matches_dump ,
2017-08-31 17:59:14 +02:00
. actions_dump = mlxsw_sp_dpipe_table_host_actions_dump ,
2017-08-24 08:40:09 +02:00
. entries_dump = mlxsw_sp_dpipe_table_host4_entries_dump ,
2017-08-24 08:40:10 +02:00
. counters_set_update = mlxsw_sp_dpipe_table_host4_counters_update ,
2017-08-24 08:40:06 +02:00
. size_get = mlxsw_sp_dpipe_table_host4_size_get ,
} ;
2018-01-15 08:59:08 +01:00
# define MLXSW_SP_DPIPE_TABLE_RESOURCE_UNIT_HOST4 1
2017-08-24 08:40:06 +02:00
static int mlxsw_sp_dpipe_host4_table_init ( struct mlxsw_sp * mlxsw_sp )
{
struct devlink * devlink = priv_to_devlink ( mlxsw_sp - > core ) ;
2018-01-15 08:59:08 +01:00
int err ;
2017-08-24 08:40:06 +02:00
2018-01-15 08:59:08 +01:00
err = devlink_dpipe_table_register ( devlink ,
MLXSW_SP_DPIPE_TABLE_NAME_HOST4 ,
& mlxsw_sp_host4_ops ,
mlxsw_sp , false ) ;
if ( err )
return err ;
err = devlink_dpipe_table_resource_set ( devlink ,
MLXSW_SP_DPIPE_TABLE_NAME_HOST4 ,
MLXSW_SP_RESOURCE_KVD_HASH_SINGLE ,
MLXSW_SP_DPIPE_TABLE_RESOURCE_UNIT_HOST4 ) ;
if ( err )
goto err_resource_set ;
return 0 ;
err_resource_set :
devlink_dpipe_table_unregister ( devlink ,
MLXSW_SP_DPIPE_TABLE_NAME_HOST4 ) ;
return err ;
2017-08-24 08:40:06 +02:00
}
static void mlxsw_sp_dpipe_host4_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_HOST4 ) ;
}
2017-08-31 17:59:14 +02:00
static int
mlxsw_sp_dpipe_table_host6_matches_dump ( void * priv , struct sk_buff * skb )
{
return mlxsw_sp_dpipe_table_host_matches_dump ( skb , AF_INET6 ) ;
}
2017-08-31 17:59:17 +02:00
static int
mlxsw_sp_dpipe_table_host6_entries_dump ( void * priv , bool counters_enabled ,
struct devlink_dpipe_dump_ctx * dump_ctx )
{
struct mlxsw_sp * mlxsw_sp = priv ;
return mlxsw_sp_dpipe_table_host_entries_dump ( mlxsw_sp ,
counters_enabled ,
dump_ctx , AF_INET6 ) ;
}
2017-08-31 17:59:19 +02:00
static int mlxsw_sp_dpipe_table_host6_counters_update ( void * priv , bool enable )
{
struct mlxsw_sp * mlxsw_sp = priv ;
mlxsw_sp_dpipe_table_host_counters_update ( mlxsw_sp , enable , AF_INET6 ) ;
return 0 ;
}
2017-08-31 17:59:14 +02:00
static u64 mlxsw_sp_dpipe_table_host6_size_get ( void * priv )
{
struct mlxsw_sp * mlxsw_sp = priv ;
return mlxsw_sp_dpipe_table_host_size_get ( mlxsw_sp , AF_INET6 ) ;
}
static struct devlink_dpipe_table_ops mlxsw_sp_host6_ops = {
. matches_dump = mlxsw_sp_dpipe_table_host6_matches_dump ,
. actions_dump = mlxsw_sp_dpipe_table_host_actions_dump ,
2017-08-31 17:59:17 +02:00
. entries_dump = mlxsw_sp_dpipe_table_host6_entries_dump ,
2017-08-31 17:59:19 +02:00
. counters_set_update = mlxsw_sp_dpipe_table_host6_counters_update ,
2017-08-31 17:59:14 +02:00
. size_get = mlxsw_sp_dpipe_table_host6_size_get ,
} ;
2018-01-15 08:59:08 +01:00
# define MLXSW_SP_DPIPE_TABLE_RESOURCE_UNIT_HOST6 2
2017-08-31 17:59:14 +02:00
static int mlxsw_sp_dpipe_host6_table_init ( struct mlxsw_sp * mlxsw_sp )
{
struct devlink * devlink = priv_to_devlink ( mlxsw_sp - > core ) ;
2018-01-15 08:59:08 +01:00
int err ;
2017-08-31 17:59:14 +02:00
2018-01-15 08:59:08 +01:00
err = devlink_dpipe_table_register ( devlink ,
MLXSW_SP_DPIPE_TABLE_NAME_HOST6 ,
& mlxsw_sp_host6_ops ,
mlxsw_sp , false ) ;
if ( err )
return err ;
err = devlink_dpipe_table_resource_set ( devlink ,
MLXSW_SP_DPIPE_TABLE_NAME_HOST6 ,
MLXSW_SP_RESOURCE_KVD_HASH_DOUBLE ,
MLXSW_SP_DPIPE_TABLE_RESOURCE_UNIT_HOST6 ) ;
if ( err )
goto err_resource_set ;
return 0 ;
err_resource_set :
devlink_dpipe_table_unregister ( devlink ,
MLXSW_SP_DPIPE_TABLE_NAME_HOST6 ) ;
return err ;
2017-08-31 17:59:14 +02:00
}
static void mlxsw_sp_dpipe_host6_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_HOST6 ) ;
}
2017-09-25 10:32:26 +02:00
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 ;
2017-10-22 23:11:43 +02:00
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_SIZE ;
2017-09-25 10:32:26 +02:00
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 ;
}
2017-09-25 10:32:29 +02:00
enum mlxsw_sp_dpipe_table_adj_match {
MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_INDEX ,
2017-10-22 23:11:43 +02:00
MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_SIZE ,
2017-09-25 10:32:29 +02:00
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 ;
2017-10-22 23:11:43 +02:00
match = & matches [ MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_SIZE ] ;
match - > type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT ;
match - > header = & mlxsw_sp_dpipe_header_metadata ;
match - > field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ADJ_SIZE ;
2017-09-25 10:32:29 +02:00
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 ] ;
2017-10-22 23:11:43 +02:00
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_SIZE ] ;
match_value = & match_values [ MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_SIZE ] ;
2017-09-25 10:32:29 +02:00
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 ,
2017-10-22 23:11:43 +02:00
u32 adj_index , u32 adj_size ,
u32 adj_hash_index , unsigned char * ha ,
2017-09-25 10:32:29 +02:00
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 ;
2017-10-22 23:11:43 +02:00
value = & entry - > match_values [ MLXSW_SP_DPIPE_TABLE_ADJ_MATCH_SIZE ] ;
p_index = value - > value ;
* p_index = adj_size ;
2017-09-25 10:32:29 +02:00
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 ;
2017-10-22 23:11:43 +02:00
u32 adj_size = 0 ;
2017-09-25 10:32:29 +02:00
int err ;
2017-10-22 23:11:43 +02:00
mlxsw_sp_nexthop_indexes ( nh , & adj_index , & adj_size , & adj_hash_index ) ;
__mlxsw_sp_dpipe_table_adj_entry_fill ( entry , adj_index , adj_size ,
2017-09-25 10:32:29 +02:00
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 ;
2017-10-24 10:11:42 +02:00
nh_count = 0 ;
2017-09-25 10:32:29 +02:00
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 ;
}
2017-09-25 10:32:30 +02:00
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 ;
2017-10-22 23:11:43 +02:00
u32 adj_size = 0 ;
2017-09-25 10:32:30 +02:00
mlxsw_sp_nexthop_for_each ( nh , mlxsw_sp - > router ) {
if ( ! mlxsw_sp_nexthop_offload ( nh ) | |
mlxsw_sp_nexthop_group_has_ipip ( nh ) )
continue ;
2017-10-22 23:11:43 +02:00
mlxsw_sp_nexthop_indexes ( nh , & adj_index , & adj_size ,
& adj_hash_index ) ;
2017-09-25 10:32:30 +02:00
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 ;
}
2017-09-25 10:32:26 +02:00
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 ,
2017-09-25 10:32:29 +02:00
. entries_dump = mlxsw_sp_dpipe_table_adj_entries_dump ,
2017-09-25 10:32:30 +02:00
. counters_set_update = mlxsw_sp_dpipe_table_adj_counters_update ,
2017-09-25 10:32:26 +02:00
. size_get = mlxsw_sp_dpipe_table_adj_size_get ,
} ;
2018-01-15 08:59:08 +01:00
# define MLXSW_SP_DPIPE_TABLE_RESOURCE_UNIT_ADJ 1
2017-09-25 10:32:26 +02:00
static int mlxsw_sp_dpipe_adj_table_init ( struct mlxsw_sp * mlxsw_sp )
{
struct devlink * devlink = priv_to_devlink ( mlxsw_sp - > core ) ;
2018-01-15 08:59:08 +01:00
int err ;
2017-09-25 10:32:26 +02:00
2018-01-15 08:59:08 +01:00
err = devlink_dpipe_table_register ( devlink ,
MLXSW_SP_DPIPE_TABLE_NAME_ADJ ,
& mlxsw_sp_dpipe_table_adj_ops ,
mlxsw_sp , false ) ;
if ( err )
return err ;
err = devlink_dpipe_table_resource_set ( devlink ,
MLXSW_SP_DPIPE_TABLE_NAME_ADJ ,
MLXSW_SP_RESOURCE_KVD_LINEAR ,
MLXSW_SP_DPIPE_TABLE_RESOURCE_UNIT_ADJ ) ;
if ( err )
goto err_resource_set ;
return 0 ;
err_resource_set :
devlink_dpipe_table_unregister ( devlink ,
MLXSW_SP_DPIPE_TABLE_NAME_ADJ ) ;
return err ;
2017-09-25 10:32:26 +02:00
}
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 ) ;
}
2017-03-28 17:24:12 +02:00
int mlxsw_sp_dpipe_init ( struct mlxsw_sp * mlxsw_sp )
{
2017-03-28 17:24:13 +02:00
struct devlink * devlink = priv_to_devlink ( mlxsw_sp - > core ) ;
int err ;
err = devlink_dpipe_headers_register ( devlink ,
& mlxsw_sp_dpipe_headers ) ;
if ( err )
return err ;
err = mlxsw_sp_dpipe_erif_table_init ( mlxsw_sp ) ;
if ( err )
2017-08-24 08:40:05 +02:00
goto err_erif_table_init ;
2017-08-24 08:40:06 +02:00
err = mlxsw_sp_dpipe_host4_table_init ( mlxsw_sp ) ;
if ( err )
goto err_host4_table_init ;
2017-08-31 17:59:14 +02:00
err = mlxsw_sp_dpipe_host6_table_init ( mlxsw_sp ) ;
if ( err )
goto err_host6_table_init ;
2017-03-28 17:24:13 +02:00
2017-09-25 10:32:26 +02:00
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 ) ;
2017-08-31 17:59:14 +02:00
err_host6_table_init :
mlxsw_sp_dpipe_host4_table_fini ( mlxsw_sp ) ;
2017-08-24 08:40:06 +02:00
err_host4_table_init :
mlxsw_sp_dpipe_erif_table_fini ( mlxsw_sp ) ;
2017-08-24 08:40:05 +02:00
err_erif_table_init :
2017-03-28 17:24:13 +02:00
devlink_dpipe_headers_unregister ( priv_to_devlink ( mlxsw_sp - > core ) ) ;
return err ;
2017-03-28 17:24:12 +02:00
}
void mlxsw_sp_dpipe_fini ( struct mlxsw_sp * mlxsw_sp )
{
2017-03-28 17:24:13 +02:00
struct devlink * devlink = priv_to_devlink ( mlxsw_sp - > core ) ;
2017-09-25 10:32:26 +02:00
mlxsw_sp_dpipe_adj_table_fini ( mlxsw_sp ) ;
2017-08-31 17:59:14 +02:00
mlxsw_sp_dpipe_host6_table_fini ( mlxsw_sp ) ;
2017-08-24 08:40:06 +02:00
mlxsw_sp_dpipe_host4_table_fini ( mlxsw_sp ) ;
2017-03-28 17:24:13 +02:00
mlxsw_sp_dpipe_erif_table_fini ( mlxsw_sp ) ;
devlink_dpipe_headers_unregister ( devlink ) ;
2017-03-28 17:24:12 +02:00
}