2023-08-28 08:16:47 +02:00
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright ( c ) 2016 Mellanox Technologies . All rights reserved .
* Copyright ( c ) 2016 Jiri Pirko < jiri @ mellanox . com >
*/
# include "devl_internal.h"
static struct devlink_dpipe_field devlink_dpipe_fields_ethernet [ ] = {
{
. name = " destination mac " ,
. id = DEVLINK_DPIPE_FIELD_ETHERNET_DST_MAC ,
. bitwidth = 48 ,
} ,
} ;
struct devlink_dpipe_header devlink_dpipe_header_ethernet = {
. name = " ethernet " ,
. id = DEVLINK_DPIPE_HEADER_ETHERNET ,
. fields = devlink_dpipe_fields_ethernet ,
. fields_count = ARRAY_SIZE ( devlink_dpipe_fields_ethernet ) ,
. global = true ,
} ;
EXPORT_SYMBOL_GPL ( devlink_dpipe_header_ethernet ) ;
static struct devlink_dpipe_field devlink_dpipe_fields_ipv4 [ ] = {
{
. name = " destination ip " ,
. id = DEVLINK_DPIPE_FIELD_IPV4_DST_IP ,
. bitwidth = 32 ,
} ,
} ;
struct devlink_dpipe_header devlink_dpipe_header_ipv4 = {
. name = " ipv4 " ,
. id = DEVLINK_DPIPE_HEADER_IPV4 ,
. fields = devlink_dpipe_fields_ipv4 ,
. fields_count = ARRAY_SIZE ( devlink_dpipe_fields_ipv4 ) ,
. global = true ,
} ;
EXPORT_SYMBOL_GPL ( devlink_dpipe_header_ipv4 ) ;
static struct devlink_dpipe_field devlink_dpipe_fields_ipv6 [ ] = {
{
. name = " destination ip " ,
. id = DEVLINK_DPIPE_FIELD_IPV6_DST_IP ,
. bitwidth = 128 ,
} ,
} ;
struct devlink_dpipe_header devlink_dpipe_header_ipv6 = {
. name = " ipv6 " ,
. id = DEVLINK_DPIPE_HEADER_IPV6 ,
. fields = devlink_dpipe_fields_ipv6 ,
. fields_count = ARRAY_SIZE ( devlink_dpipe_fields_ipv6 ) ,
. global = true ,
} ;
EXPORT_SYMBOL_GPL ( devlink_dpipe_header_ipv6 ) ;
int devlink_dpipe_match_put ( struct sk_buff * skb ,
struct devlink_dpipe_match * match )
{
struct devlink_dpipe_header * header = match - > header ;
struct devlink_dpipe_field * field = & header - > fields [ match - > field_id ] ;
struct nlattr * match_attr ;
match_attr = nla_nest_start_noflag ( skb , DEVLINK_ATTR_DPIPE_MATCH ) ;
if ( ! match_attr )
return - EMSGSIZE ;
if ( nla_put_u32 ( skb , DEVLINK_ATTR_DPIPE_MATCH_TYPE , match - > type ) | |
nla_put_u32 ( skb , DEVLINK_ATTR_DPIPE_HEADER_INDEX , match - > header_index ) | |
nla_put_u32 ( skb , DEVLINK_ATTR_DPIPE_HEADER_ID , header - > id ) | |
nla_put_u32 ( skb , DEVLINK_ATTR_DPIPE_FIELD_ID , field - > id ) | |
nla_put_u8 ( skb , DEVLINK_ATTR_DPIPE_HEADER_GLOBAL , header - > global ) )
goto nla_put_failure ;
nla_nest_end ( skb , match_attr ) ;
return 0 ;
nla_put_failure :
nla_nest_cancel ( skb , match_attr ) ;
return - EMSGSIZE ;
}
EXPORT_SYMBOL_GPL ( devlink_dpipe_match_put ) ;
static int devlink_dpipe_matches_put ( struct devlink_dpipe_table * table ,
struct sk_buff * skb )
{
struct nlattr * matches_attr ;
matches_attr = nla_nest_start_noflag ( skb ,
DEVLINK_ATTR_DPIPE_TABLE_MATCHES ) ;
if ( ! matches_attr )
return - EMSGSIZE ;
if ( table - > table_ops - > matches_dump ( table - > priv , skb ) )
goto nla_put_failure ;
nla_nest_end ( skb , matches_attr ) ;
return 0 ;
nla_put_failure :
nla_nest_cancel ( skb , matches_attr ) ;
return - EMSGSIZE ;
}
int devlink_dpipe_action_put ( struct sk_buff * skb ,
struct devlink_dpipe_action * action )
{
struct devlink_dpipe_header * header = action - > header ;
struct devlink_dpipe_field * field = & header - > fields [ action - > field_id ] ;
struct nlattr * action_attr ;
action_attr = nla_nest_start_noflag ( skb , DEVLINK_ATTR_DPIPE_ACTION ) ;
if ( ! action_attr )
return - EMSGSIZE ;
if ( nla_put_u32 ( skb , DEVLINK_ATTR_DPIPE_ACTION_TYPE , action - > type ) | |
nla_put_u32 ( skb , DEVLINK_ATTR_DPIPE_HEADER_INDEX , action - > header_index ) | |
nla_put_u32 ( skb , DEVLINK_ATTR_DPIPE_HEADER_ID , header - > id ) | |
nla_put_u32 ( skb , DEVLINK_ATTR_DPIPE_FIELD_ID , field - > id ) | |
nla_put_u8 ( skb , DEVLINK_ATTR_DPIPE_HEADER_GLOBAL , header - > global ) )
goto nla_put_failure ;
nla_nest_end ( skb , action_attr ) ;
return 0 ;
nla_put_failure :
nla_nest_cancel ( skb , action_attr ) ;
return - EMSGSIZE ;
}
EXPORT_SYMBOL_GPL ( devlink_dpipe_action_put ) ;
static int devlink_dpipe_actions_put ( struct devlink_dpipe_table * table ,
struct sk_buff * skb )
{
struct nlattr * actions_attr ;
actions_attr = nla_nest_start_noflag ( skb ,
DEVLINK_ATTR_DPIPE_TABLE_ACTIONS ) ;
if ( ! actions_attr )
return - EMSGSIZE ;
if ( table - > table_ops - > actions_dump ( table - > priv , skb ) )
goto nla_put_failure ;
nla_nest_end ( skb , actions_attr ) ;
return 0 ;
nla_put_failure :
nla_nest_cancel ( skb , actions_attr ) ;
return - EMSGSIZE ;
}
static int devlink_dpipe_table_put ( struct sk_buff * skb ,
struct devlink_dpipe_table * table )
{
struct nlattr * table_attr ;
u64 table_size ;
table_size = table - > table_ops - > size_get ( table - > priv ) ;
table_attr = nla_nest_start_noflag ( skb , DEVLINK_ATTR_DPIPE_TABLE ) ;
if ( ! table_attr )
return - EMSGSIZE ;
if ( nla_put_string ( skb , DEVLINK_ATTR_DPIPE_TABLE_NAME , table - > name ) | |
nla_put_u64_64bit ( skb , DEVLINK_ATTR_DPIPE_TABLE_SIZE , table_size ,
DEVLINK_ATTR_PAD ) )
goto nla_put_failure ;
if ( nla_put_u8 ( skb , DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED ,
table - > counters_enabled ) )
goto nla_put_failure ;
if ( table - > resource_valid ) {
if ( nla_put_u64_64bit ( skb , DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_ID ,
table - > resource_id , DEVLINK_ATTR_PAD ) | |
nla_put_u64_64bit ( skb , DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_UNITS ,
table - > resource_units , DEVLINK_ATTR_PAD ) )
goto nla_put_failure ;
}
if ( devlink_dpipe_matches_put ( table , skb ) )
goto nla_put_failure ;
if ( devlink_dpipe_actions_put ( table , skb ) )
goto nla_put_failure ;
nla_nest_end ( skb , table_attr ) ;
return 0 ;
nla_put_failure :
nla_nest_cancel ( skb , table_attr ) ;
return - EMSGSIZE ;
}
static int devlink_dpipe_send_and_alloc_skb ( struct sk_buff * * pskb ,
struct genl_info * info )
{
int err ;
if ( * pskb ) {
err = genlmsg_reply ( * pskb , info ) ;
if ( err )
return err ;
}
* pskb = genlmsg_new ( GENLMSG_DEFAULT_SIZE , GFP_KERNEL ) ;
if ( ! * pskb )
return - ENOMEM ;
return 0 ;
}
static int devlink_dpipe_tables_fill ( struct genl_info * info ,
enum devlink_command cmd , int flags ,
struct list_head * dpipe_tables ,
const char * table_name )
{
struct devlink * devlink = info - > user_ptr [ 0 ] ;
struct devlink_dpipe_table * table ;
struct nlattr * tables_attr ;
struct sk_buff * skb = NULL ;
struct nlmsghdr * nlh ;
bool incomplete ;
void * hdr ;
int i ;
int err ;
table = list_first_entry ( dpipe_tables ,
struct devlink_dpipe_table , list ) ;
start_again :
err = devlink_dpipe_send_and_alloc_skb ( & skb , info ) ;
if ( err )
return err ;
hdr = genlmsg_put ( skb , info - > snd_portid , info - > snd_seq ,
& devlink_nl_family , NLM_F_MULTI , cmd ) ;
if ( ! hdr ) {
nlmsg_free ( skb ) ;
return - EMSGSIZE ;
}
if ( devlink_nl_put_handle ( skb , devlink ) )
goto nla_put_failure ;
tables_attr = nla_nest_start_noflag ( skb , DEVLINK_ATTR_DPIPE_TABLES ) ;
if ( ! tables_attr )
goto nla_put_failure ;
i = 0 ;
incomplete = false ;
list_for_each_entry_from ( table , dpipe_tables , list ) {
if ( ! table_name ) {
err = devlink_dpipe_table_put ( skb , table ) ;
if ( err ) {
if ( ! i )
goto err_table_put ;
incomplete = true ;
break ;
}
} else {
if ( ! strcmp ( table - > name , table_name ) ) {
err = devlink_dpipe_table_put ( skb , table ) ;
if ( err )
break ;
}
}
i + + ;
}
nla_nest_end ( skb , tables_attr ) ;
genlmsg_end ( skb , hdr ) ;
if ( incomplete )
goto start_again ;
send_done :
nlh = nlmsg_put ( skb , info - > snd_portid , info - > snd_seq ,
NLMSG_DONE , 0 , flags | NLM_F_MULTI ) ;
if ( ! nlh ) {
err = devlink_dpipe_send_and_alloc_skb ( & skb , info ) ;
if ( err )
return err ;
goto send_done ;
}
return genlmsg_reply ( skb , info ) ;
nla_put_failure :
err = - EMSGSIZE ;
err_table_put :
nlmsg_free ( skb ) ;
return err ;
}
2023-10-21 13:27:08 +02:00
int devlink_nl_dpipe_table_get_doit ( struct sk_buff * skb , struct genl_info * info )
2023-08-28 08:16:47 +02:00
{
struct devlink * devlink = info - > user_ptr [ 0 ] ;
const char * table_name = NULL ;
if ( info - > attrs [ DEVLINK_ATTR_DPIPE_TABLE_NAME ] )
table_name = nla_data ( info - > attrs [ DEVLINK_ATTR_DPIPE_TABLE_NAME ] ) ;
return devlink_dpipe_tables_fill ( info , DEVLINK_CMD_DPIPE_TABLE_GET , 0 ,
& devlink - > dpipe_table_list ,
table_name ) ;
}
static int devlink_dpipe_value_put ( struct sk_buff * skb ,
struct devlink_dpipe_value * value )
{
if ( nla_put ( skb , DEVLINK_ATTR_DPIPE_VALUE ,
value - > value_size , value - > value ) )
return - EMSGSIZE ;
if ( value - > mask )
if ( nla_put ( skb , DEVLINK_ATTR_DPIPE_VALUE_MASK ,
value - > value_size , value - > mask ) )
return - EMSGSIZE ;
if ( value - > mapping_valid )
if ( nla_put_u32 ( skb , DEVLINK_ATTR_DPIPE_VALUE_MAPPING ,
value - > mapping_value ) )
return - EMSGSIZE ;
return 0 ;
}
static int devlink_dpipe_action_value_put ( struct sk_buff * skb ,
struct devlink_dpipe_value * value )
{
if ( ! value - > action )
return - EINVAL ;
if ( devlink_dpipe_action_put ( skb , value - > action ) )
return - EMSGSIZE ;
if ( devlink_dpipe_value_put ( skb , value ) )
return - EMSGSIZE ;
return 0 ;
}
static int devlink_dpipe_action_values_put ( struct sk_buff * skb ,
struct devlink_dpipe_value * values ,
unsigned int values_count )
{
struct nlattr * action_attr ;
int i ;
int err ;
for ( i = 0 ; i < values_count ; i + + ) {
action_attr = nla_nest_start_noflag ( skb ,
DEVLINK_ATTR_DPIPE_ACTION_VALUE ) ;
if ( ! action_attr )
return - EMSGSIZE ;
err = devlink_dpipe_action_value_put ( skb , & values [ i ] ) ;
if ( err )
goto err_action_value_put ;
nla_nest_end ( skb , action_attr ) ;
}
return 0 ;
err_action_value_put :
nla_nest_cancel ( skb , action_attr ) ;
return err ;
}
static int devlink_dpipe_match_value_put ( struct sk_buff * skb ,
struct devlink_dpipe_value * value )
{
if ( ! value - > match )
return - EINVAL ;
if ( devlink_dpipe_match_put ( skb , value - > match ) )
return - EMSGSIZE ;
if ( devlink_dpipe_value_put ( skb , value ) )
return - EMSGSIZE ;
return 0 ;
}
static int devlink_dpipe_match_values_put ( struct sk_buff * skb ,
struct devlink_dpipe_value * values ,
unsigned int values_count )
{
struct nlattr * match_attr ;
int i ;
int err ;
for ( i = 0 ; i < values_count ; i + + ) {
match_attr = nla_nest_start_noflag ( skb ,
DEVLINK_ATTR_DPIPE_MATCH_VALUE ) ;
if ( ! match_attr )
return - EMSGSIZE ;
err = devlink_dpipe_match_value_put ( skb , & values [ i ] ) ;
if ( err )
goto err_match_value_put ;
nla_nest_end ( skb , match_attr ) ;
}
return 0 ;
err_match_value_put :
nla_nest_cancel ( skb , match_attr ) ;
return err ;
}
static int devlink_dpipe_entry_put ( struct sk_buff * skb ,
struct devlink_dpipe_entry * entry )
{
struct nlattr * entry_attr , * matches_attr , * actions_attr ;
int err ;
entry_attr = nla_nest_start_noflag ( skb , DEVLINK_ATTR_DPIPE_ENTRY ) ;
if ( ! entry_attr )
return - EMSGSIZE ;
if ( nla_put_u64_64bit ( skb , DEVLINK_ATTR_DPIPE_ENTRY_INDEX , entry - > index ,
DEVLINK_ATTR_PAD ) )
goto nla_put_failure ;
if ( entry - > counter_valid )
if ( nla_put_u64_64bit ( skb , DEVLINK_ATTR_DPIPE_ENTRY_COUNTER ,
entry - > counter , DEVLINK_ATTR_PAD ) )
goto nla_put_failure ;
matches_attr = nla_nest_start_noflag ( skb ,
DEVLINK_ATTR_DPIPE_ENTRY_MATCH_VALUES ) ;
if ( ! matches_attr )
goto nla_put_failure ;
err = devlink_dpipe_match_values_put ( skb , entry - > match_values ,
entry - > match_values_count ) ;
if ( err ) {
nla_nest_cancel ( skb , matches_attr ) ;
goto err_match_values_put ;
}
nla_nest_end ( skb , matches_attr ) ;
actions_attr = nla_nest_start_noflag ( skb ,
DEVLINK_ATTR_DPIPE_ENTRY_ACTION_VALUES ) ;
if ( ! actions_attr )
goto nla_put_failure ;
err = devlink_dpipe_action_values_put ( skb , entry - > action_values ,
entry - > action_values_count ) ;
if ( err ) {
nla_nest_cancel ( skb , actions_attr ) ;
goto err_action_values_put ;
}
nla_nest_end ( skb , actions_attr ) ;
nla_nest_end ( skb , entry_attr ) ;
return 0 ;
nla_put_failure :
err = - EMSGSIZE ;
err_match_values_put :
err_action_values_put :
nla_nest_cancel ( skb , entry_attr ) ;
return err ;
}
static struct devlink_dpipe_table *
devlink_dpipe_table_find ( struct list_head * dpipe_tables ,
const char * table_name , struct devlink * devlink )
{
struct devlink_dpipe_table * table ;
list_for_each_entry_rcu ( table , dpipe_tables , list ,
lockdep_is_held ( & devlink - > lock ) ) {
if ( ! strcmp ( table - > name , table_name ) )
return table ;
}
return NULL ;
}
int devlink_dpipe_entry_ctx_prepare ( struct devlink_dpipe_dump_ctx * dump_ctx )
{
struct devlink * devlink ;
int err ;
err = devlink_dpipe_send_and_alloc_skb ( & dump_ctx - > skb ,
dump_ctx - > info ) ;
if ( err )
return err ;
dump_ctx - > hdr = genlmsg_put ( dump_ctx - > skb ,
dump_ctx - > info - > snd_portid ,
dump_ctx - > info - > snd_seq ,
& devlink_nl_family , NLM_F_MULTI ,
dump_ctx - > cmd ) ;
if ( ! dump_ctx - > hdr )
goto nla_put_failure ;
devlink = dump_ctx - > info - > user_ptr [ 0 ] ;
if ( devlink_nl_put_handle ( dump_ctx - > skb , devlink ) )
goto nla_put_failure ;
dump_ctx - > nest = nla_nest_start_noflag ( dump_ctx - > skb ,
DEVLINK_ATTR_DPIPE_ENTRIES ) ;
if ( ! dump_ctx - > nest )
goto nla_put_failure ;
return 0 ;
nla_put_failure :
nlmsg_free ( dump_ctx - > skb ) ;
return - EMSGSIZE ;
}
EXPORT_SYMBOL_GPL ( devlink_dpipe_entry_ctx_prepare ) ;
int devlink_dpipe_entry_ctx_append ( struct devlink_dpipe_dump_ctx * dump_ctx ,
struct devlink_dpipe_entry * entry )
{
return devlink_dpipe_entry_put ( dump_ctx - > skb , entry ) ;
}
EXPORT_SYMBOL_GPL ( devlink_dpipe_entry_ctx_append ) ;
int devlink_dpipe_entry_ctx_close ( struct devlink_dpipe_dump_ctx * dump_ctx )
{
nla_nest_end ( dump_ctx - > skb , dump_ctx - > nest ) ;
genlmsg_end ( dump_ctx - > skb , dump_ctx - > hdr ) ;
return 0 ;
}
EXPORT_SYMBOL_GPL ( devlink_dpipe_entry_ctx_close ) ;
void devlink_dpipe_entry_clear ( struct devlink_dpipe_entry * entry )
{
unsigned int value_count , value_index ;
struct devlink_dpipe_value * value ;
value = entry - > action_values ;
value_count = entry - > action_values_count ;
for ( value_index = 0 ; value_index < value_count ; value_index + + ) {
kfree ( value [ value_index ] . value ) ;
kfree ( value [ value_index ] . mask ) ;
}
value = entry - > match_values ;
value_count = entry - > match_values_count ;
for ( value_index = 0 ; value_index < value_count ; value_index + + ) {
kfree ( value [ value_index ] . value ) ;
kfree ( value [ value_index ] . mask ) ;
}
}
EXPORT_SYMBOL_GPL ( devlink_dpipe_entry_clear ) ;
static int devlink_dpipe_entries_fill ( struct genl_info * info ,
enum devlink_command cmd , int flags ,
struct devlink_dpipe_table * table )
{
struct devlink_dpipe_dump_ctx dump_ctx ;
struct nlmsghdr * nlh ;
int err ;
dump_ctx . skb = NULL ;
dump_ctx . cmd = cmd ;
dump_ctx . info = info ;
err = table - > table_ops - > entries_dump ( table - > priv ,
table - > counters_enabled ,
& dump_ctx ) ;
if ( err )
return err ;
send_done :
nlh = nlmsg_put ( dump_ctx . skb , info - > snd_portid , info - > snd_seq ,
NLMSG_DONE , 0 , flags | NLM_F_MULTI ) ;
if ( ! nlh ) {
err = devlink_dpipe_send_and_alloc_skb ( & dump_ctx . skb , info ) ;
if ( err )
return err ;
goto send_done ;
}
return genlmsg_reply ( dump_ctx . skb , info ) ;
}
2023-10-21 13:27:08 +02:00
int devlink_nl_dpipe_entries_get_doit ( struct sk_buff * skb ,
struct genl_info * info )
2023-08-28 08:16:47 +02:00
{
struct devlink * devlink = info - > user_ptr [ 0 ] ;
struct devlink_dpipe_table * table ;
const char * table_name ;
if ( GENL_REQ_ATTR_CHECK ( info , DEVLINK_ATTR_DPIPE_TABLE_NAME ) )
return - EINVAL ;
table_name = nla_data ( info - > attrs [ DEVLINK_ATTR_DPIPE_TABLE_NAME ] ) ;
table = devlink_dpipe_table_find ( & devlink - > dpipe_table_list ,
table_name , devlink ) ;
if ( ! table )
return - EINVAL ;
if ( ! table - > table_ops - > entries_dump )
return - EINVAL ;
return devlink_dpipe_entries_fill ( info , DEVLINK_CMD_DPIPE_ENTRIES_GET ,
0 , table ) ;
}
static int devlink_dpipe_fields_put ( struct sk_buff * skb ,
const struct devlink_dpipe_header * header )
{
struct devlink_dpipe_field * field ;
struct nlattr * field_attr ;
int i ;
for ( i = 0 ; i < header - > fields_count ; i + + ) {
field = & header - > fields [ i ] ;
field_attr = nla_nest_start_noflag ( skb ,
DEVLINK_ATTR_DPIPE_FIELD ) ;
if ( ! field_attr )
return - EMSGSIZE ;
if ( nla_put_string ( skb , DEVLINK_ATTR_DPIPE_FIELD_NAME , field - > name ) | |
nla_put_u32 ( skb , DEVLINK_ATTR_DPIPE_FIELD_ID , field - > id ) | |
nla_put_u32 ( skb , DEVLINK_ATTR_DPIPE_FIELD_BITWIDTH , field - > bitwidth ) | |
nla_put_u32 ( skb , DEVLINK_ATTR_DPIPE_FIELD_MAPPING_TYPE , field - > mapping_type ) )
goto nla_put_failure ;
nla_nest_end ( skb , field_attr ) ;
}
return 0 ;
nla_put_failure :
nla_nest_cancel ( skb , field_attr ) ;
return - EMSGSIZE ;
}
static int devlink_dpipe_header_put ( struct sk_buff * skb ,
struct devlink_dpipe_header * header )
{
struct nlattr * fields_attr , * header_attr ;
int err ;
header_attr = nla_nest_start_noflag ( skb , DEVLINK_ATTR_DPIPE_HEADER ) ;
if ( ! header_attr )
return - EMSGSIZE ;
if ( nla_put_string ( skb , DEVLINK_ATTR_DPIPE_HEADER_NAME , header - > name ) | |
nla_put_u32 ( skb , DEVLINK_ATTR_DPIPE_HEADER_ID , header - > id ) | |
nla_put_u8 ( skb , DEVLINK_ATTR_DPIPE_HEADER_GLOBAL , header - > global ) )
goto nla_put_failure ;
fields_attr = nla_nest_start_noflag ( skb ,
DEVLINK_ATTR_DPIPE_HEADER_FIELDS ) ;
if ( ! fields_attr )
goto nla_put_failure ;
err = devlink_dpipe_fields_put ( skb , header ) ;
if ( err ) {
nla_nest_cancel ( skb , fields_attr ) ;
goto nla_put_failure ;
}
nla_nest_end ( skb , fields_attr ) ;
nla_nest_end ( skb , header_attr ) ;
return 0 ;
nla_put_failure :
err = - EMSGSIZE ;
nla_nest_cancel ( skb , header_attr ) ;
return err ;
}
static int devlink_dpipe_headers_fill ( struct genl_info * info ,
enum devlink_command cmd , int flags ,
struct devlink_dpipe_headers *
dpipe_headers )
{
struct devlink * devlink = info - > user_ptr [ 0 ] ;
struct nlattr * headers_attr ;
struct sk_buff * skb = NULL ;
struct nlmsghdr * nlh ;
void * hdr ;
int i , j ;
int err ;
i = 0 ;
start_again :
err = devlink_dpipe_send_and_alloc_skb ( & skb , info ) ;
if ( err )
return err ;
hdr = genlmsg_put ( skb , info - > snd_portid , info - > snd_seq ,
& devlink_nl_family , NLM_F_MULTI , cmd ) ;
if ( ! hdr ) {
nlmsg_free ( skb ) ;
return - EMSGSIZE ;
}
if ( devlink_nl_put_handle ( skb , devlink ) )
goto nla_put_failure ;
headers_attr = nla_nest_start_noflag ( skb , DEVLINK_ATTR_DPIPE_HEADERS ) ;
if ( ! headers_attr )
goto nla_put_failure ;
j = 0 ;
for ( ; i < dpipe_headers - > headers_count ; i + + ) {
err = devlink_dpipe_header_put ( skb , dpipe_headers - > headers [ i ] ) ;
if ( err ) {
if ( ! j )
goto err_table_put ;
break ;
}
j + + ;
}
nla_nest_end ( skb , headers_attr ) ;
genlmsg_end ( skb , hdr ) ;
if ( i ! = dpipe_headers - > headers_count )
goto start_again ;
send_done :
nlh = nlmsg_put ( skb , info - > snd_portid , info - > snd_seq ,
NLMSG_DONE , 0 , flags | NLM_F_MULTI ) ;
if ( ! nlh ) {
err = devlink_dpipe_send_and_alloc_skb ( & skb , info ) ;
if ( err )
return err ;
goto send_done ;
}
return genlmsg_reply ( skb , info ) ;
nla_put_failure :
err = - EMSGSIZE ;
err_table_put :
nlmsg_free ( skb ) ;
return err ;
}
2023-10-21 13:27:08 +02:00
int devlink_nl_dpipe_headers_get_doit ( struct sk_buff * skb ,
struct genl_info * info )
2023-08-28 08:16:47 +02:00
{
struct devlink * devlink = info - > user_ptr [ 0 ] ;
if ( ! devlink - > dpipe_headers )
return - EOPNOTSUPP ;
return devlink_dpipe_headers_fill ( info , DEVLINK_CMD_DPIPE_HEADERS_GET ,
0 , devlink - > dpipe_headers ) ;
}
static int devlink_dpipe_table_counters_set ( struct devlink * devlink ,
const char * table_name ,
bool enable )
{
struct devlink_dpipe_table * table ;
table = devlink_dpipe_table_find ( & devlink - > dpipe_table_list ,
table_name , devlink ) ;
if ( ! table )
return - EINVAL ;
if ( table - > counter_control_extern )
return - EOPNOTSUPP ;
if ( ! ( table - > counters_enabled ^ enable ) )
return 0 ;
table - > counters_enabled = enable ;
if ( table - > table_ops - > counters_set_update )
table - > table_ops - > counters_set_update ( table - > priv , enable ) ;
return 0 ;
}
2023-10-21 13:27:08 +02:00
int devlink_nl_dpipe_table_counters_set_doit ( struct sk_buff * skb ,
struct genl_info * info )
2023-08-28 08:16:47 +02:00
{
struct devlink * devlink = info - > user_ptr [ 0 ] ;
const char * table_name ;
bool counters_enable ;
if ( GENL_REQ_ATTR_CHECK ( info , DEVLINK_ATTR_DPIPE_TABLE_NAME ) | |
GENL_REQ_ATTR_CHECK ( info ,
DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED ) )
return - EINVAL ;
table_name = nla_data ( info - > attrs [ DEVLINK_ATTR_DPIPE_TABLE_NAME ] ) ;
counters_enable = ! ! nla_get_u8 ( info - > attrs [ DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED ] ) ;
return devlink_dpipe_table_counters_set ( devlink , table_name ,
counters_enable ) ;
}
/**
* devl_dpipe_headers_register - register dpipe headers
*
* @ devlink : devlink
* @ dpipe_headers : dpipe header array
*
* Register the headers supported by hardware .
*/
void devl_dpipe_headers_register ( struct devlink * devlink ,
struct devlink_dpipe_headers * dpipe_headers )
{
lockdep_assert_held ( & devlink - > lock ) ;
devlink - > dpipe_headers = dpipe_headers ;
}
EXPORT_SYMBOL_GPL ( devl_dpipe_headers_register ) ;
/**
* devl_dpipe_headers_unregister - unregister dpipe headers
*
* @ devlink : devlink
*
* Unregister the headers supported by hardware .
*/
void devl_dpipe_headers_unregister ( struct devlink * devlink )
{
lockdep_assert_held ( & devlink - > lock ) ;
devlink - > dpipe_headers = NULL ;
}
EXPORT_SYMBOL_GPL ( devl_dpipe_headers_unregister ) ;
/**
* devlink_dpipe_table_counter_enabled - check if counter allocation
* required
* @ devlink : devlink
* @ table_name : tables name
*
* Used by driver to check if counter allocation is required .
* After counter allocation is turned on the table entries
* are updated to include counter statistics .
*
* After that point on the driver must respect the counter
* state so that each entry added to the table is added
* with a counter .
*/
bool devlink_dpipe_table_counter_enabled ( struct devlink * devlink ,
const char * table_name )
{
struct devlink_dpipe_table * table ;
bool enabled ;
rcu_read_lock ( ) ;
table = devlink_dpipe_table_find ( & devlink - > dpipe_table_list ,
table_name , devlink ) ;
enabled = false ;
if ( table )
enabled = table - > counters_enabled ;
rcu_read_unlock ( ) ;
return enabled ;
}
EXPORT_SYMBOL_GPL ( devlink_dpipe_table_counter_enabled ) ;
/**
* devl_dpipe_table_register - register dpipe table
*
* @ devlink : devlink
* @ table_name : table name
* @ table_ops : table ops
* @ priv : priv
* @ counter_control_extern : external control for counters
*/
int devl_dpipe_table_register ( struct devlink * devlink ,
const char * table_name ,
struct devlink_dpipe_table_ops * table_ops ,
void * priv , bool counter_control_extern )
{
struct devlink_dpipe_table * table ;
lockdep_assert_held ( & devlink - > lock ) ;
if ( WARN_ON ( ! table_ops - > size_get ) )
return - EINVAL ;
if ( devlink_dpipe_table_find ( & devlink - > dpipe_table_list , table_name ,
devlink ) )
return - EEXIST ;
table = kzalloc ( sizeof ( * table ) , GFP_KERNEL ) ;
if ( ! table )
return - ENOMEM ;
table - > name = table_name ;
table - > table_ops = table_ops ;
table - > priv = priv ;
table - > counter_control_extern = counter_control_extern ;
list_add_tail_rcu ( & table - > list , & devlink - > dpipe_table_list ) ;
return 0 ;
}
EXPORT_SYMBOL_GPL ( devl_dpipe_table_register ) ;
/**
* devl_dpipe_table_unregister - unregister dpipe table
*
* @ devlink : devlink
* @ table_name : table name
*/
void devl_dpipe_table_unregister ( struct devlink * devlink ,
const char * table_name )
{
struct devlink_dpipe_table * table ;
lockdep_assert_held ( & devlink - > lock ) ;
table = devlink_dpipe_table_find ( & devlink - > dpipe_table_list ,
table_name , devlink ) ;
if ( ! table )
return ;
list_del_rcu ( & table - > list ) ;
kfree_rcu ( table , rcu ) ;
}
EXPORT_SYMBOL_GPL ( devl_dpipe_table_unregister ) ;
/**
* devl_dpipe_table_resource_set - set the resource id
*
* @ devlink : devlink
* @ table_name : table name
* @ resource_id : resource id
* @ resource_units : number of resource ' s units consumed per table ' s entry
*/
int devl_dpipe_table_resource_set ( struct devlink * devlink ,
const char * table_name , u64 resource_id ,
u64 resource_units )
{
struct devlink_dpipe_table * table ;
table = devlink_dpipe_table_find ( & devlink - > dpipe_table_list ,
table_name , devlink ) ;
if ( ! table )
return - EINVAL ;
table - > resource_id = resource_id ;
table - > resource_units = resource_units ;
table - > resource_valid = true ;
return 0 ;
}
EXPORT_SYMBOL_GPL ( devl_dpipe_table_resource_set ) ;