2018-03-27 18:22:00 -07:00
/*
* Copyright ( c ) 2018 Cumulus Networks . All rights reserved .
* Copyright ( c ) 2018 David Ahern < dsa @ cumulusnetworks . com >
2019-04-25 15:59:43 +02:00
* Copyright ( c ) 2019 Mellanox Technologies . All rights reserved .
2018-03-27 18:22:00 -07:00
*
* This software is licensed under the GNU General License Version 2 ,
* June 1991 as shown in the file COPYING in the top - level directory of this
* source tree .
*
* THE COPYRIGHT HOLDERS AND / OR OTHER PARTIES PROVIDE THE PROGRAM " AS IS "
* WITHOUT WARRANTY OF ANY KIND , EITHER EXPRESSED OR IMPLIED , INCLUDING ,
* BUT NOT LIMITED TO , THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE . THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE
* OF THE PROGRAM IS WITH YOU . SHOULD THE PROGRAM PROVE DEFECTIVE , YOU ASSUME
* THE COST OF ALL NECESSARY SERVICING , REPAIR OR CORRECTION .
*/
2019-04-25 15:59:50 +02:00
# include <linux/debugfs.h>
2018-03-27 18:22:00 -07:00
# include <linux/device.h>
2019-04-25 15:59:51 +02:00
# include <linux/random.h>
2019-04-25 15:59:42 +02:00
# include <linux/rtnetlink.h>
2018-03-27 18:22:00 -07:00
# include <net/devlink.h>
# include "netdevsim.h"
2019-04-25 15:59:50 +02:00
static struct dentry * nsim_dev_ddir ;
static int nsim_dev_debugfs_init ( struct nsim_dev * nsim_dev )
{
2019-04-25 15:59:52 +02:00
char dev_ddir_name [ 16 ] ;
2019-04-25 15:59:50 +02:00
2019-04-25 15:59:52 +02:00
sprintf ( dev_ddir_name , DRV_NAME " %u " , nsim_dev - > nsim_bus_dev - > dev . id ) ;
2019-04-25 15:59:50 +02:00
nsim_dev - > ddir = debugfs_create_dir ( dev_ddir_name , nsim_dev_ddir ) ;
if ( IS_ERR_OR_NULL ( nsim_dev - > ddir ) )
return PTR_ERR_OR_ZERO ( nsim_dev - > ddir ) ? : - EINVAL ;
2019-04-25 15:59:52 +02:00
nsim_dev - > ports_ddir = debugfs_create_dir ( " ports " , nsim_dev - > ddir ) ;
if ( IS_ERR_OR_NULL ( nsim_dev - > ports_ddir ) )
return PTR_ERR_OR_ZERO ( nsim_dev - > ports_ddir ) ? : - EINVAL ;
2019-04-25 15:59:50 +02:00
return 0 ;
}
static void nsim_dev_debugfs_exit ( struct nsim_dev * nsim_dev )
{
2019-04-25 15:59:52 +02:00
debugfs_remove_recursive ( nsim_dev - > ports_ddir ) ;
2019-04-25 15:59:50 +02:00
debugfs_remove_recursive ( nsim_dev - > ddir ) ;
}
2019-04-25 15:59:43 +02:00
static u64 nsim_dev_ipv4_fib_resource_occ_get ( void * priv )
2018-03-27 18:22:00 -07:00
{
2019-04-25 15:59:43 +02:00
struct nsim_dev * nsim_dev = priv ;
2018-03-27 18:22:00 -07:00
2019-04-25 15:59:43 +02:00
return nsim_fib_get_val ( nsim_dev - > fib_data ,
2019-04-25 15:59:42 +02:00
NSIM_RESOURCE_IPV4_FIB , false ) ;
2018-03-27 18:22:00 -07:00
}
2019-04-25 15:59:43 +02:00
static u64 nsim_dev_ipv4_fib_rules_res_occ_get ( void * priv )
2018-03-27 18:22:00 -07:00
{
2019-04-25 15:59:43 +02:00
struct nsim_dev * nsim_dev = priv ;
2018-03-27 18:22:00 -07:00
2019-04-25 15:59:43 +02:00
return nsim_fib_get_val ( nsim_dev - > fib_data ,
2019-04-25 15:59:42 +02:00
NSIM_RESOURCE_IPV4_FIB_RULES , false ) ;
2018-03-27 18:22:00 -07:00
}
2019-04-25 15:59:43 +02:00
static u64 nsim_dev_ipv6_fib_resource_occ_get ( void * priv )
2018-03-27 18:22:00 -07:00
{
2019-04-25 15:59:43 +02:00
struct nsim_dev * nsim_dev = priv ;
2018-03-27 18:22:00 -07:00
2019-04-25 15:59:43 +02:00
return nsim_fib_get_val ( nsim_dev - > fib_data ,
2019-04-25 15:59:42 +02:00
NSIM_RESOURCE_IPV6_FIB , false ) ;
2018-03-27 18:22:00 -07:00
}
2019-04-25 15:59:43 +02:00
static u64 nsim_dev_ipv6_fib_rules_res_occ_get ( void * priv )
2018-03-27 18:22:00 -07:00
{
2019-04-25 15:59:43 +02:00
struct nsim_dev * nsim_dev = priv ;
2018-03-27 18:22:00 -07:00
2019-04-25 15:59:43 +02:00
return nsim_fib_get_val ( nsim_dev - > fib_data ,
2019-04-25 15:59:42 +02:00
NSIM_RESOURCE_IPV6_FIB_RULES , false ) ;
2018-03-27 18:22:00 -07:00
}
2019-04-25 15:59:43 +02:00
static int nsim_dev_resources_register ( struct devlink * devlink )
2018-03-27 18:22:00 -07:00
{
2019-04-25 15:59:43 +02:00
struct nsim_dev * nsim_dev = devlink_priv ( devlink ) ;
2018-03-27 18:22:00 -07:00
struct devlink_resource_size_params params = {
. size_max = ( u64 ) - 1 ,
. size_granularity = 1 ,
. unit = DEVLINK_RESOURCE_UNIT_ENTRY
} ;
int err ;
u64 n ;
/* Resources for IPv4 */
err = devlink_resource_register ( devlink , " IPv4 " , ( u64 ) - 1 ,
NSIM_RESOURCE_IPV4 ,
DEVLINK_RESOURCE_ID_PARENT_TOP ,
2018-04-05 22:13:21 +02:00
& params ) ;
2018-03-27 18:22:00 -07:00
if ( err ) {
pr_err ( " Failed to register IPv4 top resource \n " ) ;
goto out ;
}
2019-04-25 15:59:43 +02:00
n = nsim_fib_get_val ( nsim_dev - > fib_data ,
2019-04-25 15:59:42 +02:00
NSIM_RESOURCE_IPV4_FIB , true ) ;
2018-03-27 18:22:00 -07:00
err = devlink_resource_register ( devlink , " fib " , n ,
NSIM_RESOURCE_IPV4_FIB ,
2018-04-05 22:13:21 +02:00
NSIM_RESOURCE_IPV4 , & params ) ;
2018-03-27 18:22:00 -07:00
if ( err ) {
pr_err ( " Failed to register IPv4 FIB resource \n " ) ;
return err ;
}
2019-04-25 15:59:43 +02:00
n = nsim_fib_get_val ( nsim_dev - > fib_data ,
2019-04-25 15:59:42 +02:00
NSIM_RESOURCE_IPV4_FIB_RULES , true ) ;
2018-03-27 18:22:00 -07:00
err = devlink_resource_register ( devlink , " fib-rules " , n ,
NSIM_RESOURCE_IPV4_FIB_RULES ,
2018-04-05 22:13:21 +02:00
NSIM_RESOURCE_IPV4 , & params ) ;
2018-03-27 18:22:00 -07:00
if ( err ) {
pr_err ( " Failed to register IPv4 FIB rules resource \n " ) ;
return err ;
}
/* Resources for IPv6 */
err = devlink_resource_register ( devlink , " IPv6 " , ( u64 ) - 1 ,
NSIM_RESOURCE_IPV6 ,
DEVLINK_RESOURCE_ID_PARENT_TOP ,
2018-04-05 22:13:21 +02:00
& params ) ;
2018-03-27 18:22:00 -07:00
if ( err ) {
pr_err ( " Failed to register IPv6 top resource \n " ) ;
goto out ;
}
2019-04-25 15:59:43 +02:00
n = nsim_fib_get_val ( nsim_dev - > fib_data ,
2019-04-25 15:59:42 +02:00
NSIM_RESOURCE_IPV6_FIB , true ) ;
2018-03-27 18:22:00 -07:00
err = devlink_resource_register ( devlink , " fib " , n ,
NSIM_RESOURCE_IPV6_FIB ,
2018-04-05 22:13:21 +02:00
NSIM_RESOURCE_IPV6 , & params ) ;
2018-03-27 18:22:00 -07:00
if ( err ) {
pr_err ( " Failed to register IPv6 FIB resource \n " ) ;
return err ;
}
2019-04-25 15:59:43 +02:00
n = nsim_fib_get_val ( nsim_dev - > fib_data ,
2019-04-25 15:59:42 +02:00
NSIM_RESOURCE_IPV6_FIB_RULES , true ) ;
2018-03-27 18:22:00 -07:00
err = devlink_resource_register ( devlink , " fib-rules " , n ,
NSIM_RESOURCE_IPV6_FIB_RULES ,
2018-04-05 22:13:21 +02:00
NSIM_RESOURCE_IPV6 , & params ) ;
2018-03-27 18:22:00 -07:00
if ( err ) {
pr_err ( " Failed to register IPv6 FIB rules resource \n " ) ;
return err ;
}
2018-04-05 22:13:21 +02:00
devlink_resource_occ_get_register ( devlink ,
NSIM_RESOURCE_IPV4_FIB ,
2019-04-25 15:59:43 +02:00
nsim_dev_ipv4_fib_resource_occ_get ,
nsim_dev ) ;
2018-04-05 22:13:21 +02:00
devlink_resource_occ_get_register ( devlink ,
NSIM_RESOURCE_IPV4_FIB_RULES ,
2019-04-25 15:59:43 +02:00
nsim_dev_ipv4_fib_rules_res_occ_get ,
nsim_dev ) ;
2018-04-05 22:13:21 +02:00
devlink_resource_occ_get_register ( devlink ,
NSIM_RESOURCE_IPV6_FIB ,
2019-04-25 15:59:43 +02:00
nsim_dev_ipv6_fib_resource_occ_get ,
nsim_dev ) ;
2018-04-05 22:13:21 +02:00
devlink_resource_occ_get_register ( devlink ,
NSIM_RESOURCE_IPV6_FIB_RULES ,
2019-04-25 15:59:43 +02:00
nsim_dev_ipv6_fib_rules_res_occ_get ,
nsim_dev ) ;
2018-03-27 18:22:00 -07:00
out :
return err ;
}
2019-04-25 15:59:43 +02:00
static int nsim_dev_reload ( struct devlink * devlink ,
struct netlink_ext_ack * extack )
2018-03-27 18:22:00 -07:00
{
2019-04-25 15:59:43 +02:00
struct nsim_dev * nsim_dev = devlink_priv ( devlink ) ;
2018-03-27 18:22:00 -07:00
enum nsim_resource_id res_ids [ ] = {
NSIM_RESOURCE_IPV4_FIB , NSIM_RESOURCE_IPV4_FIB_RULES ,
NSIM_RESOURCE_IPV6_FIB , NSIM_RESOURCE_IPV6_FIB_RULES
} ;
int i ;
for ( i = 0 ; i < ARRAY_SIZE ( res_ids ) ; + + i ) {
int err ;
u64 val ;
err = devlink_resource_size_get ( devlink , res_ids [ i ] , & val ) ;
if ( ! err ) {
2019-04-25 15:59:43 +02:00
err = nsim_fib_set_max ( nsim_dev - > fib_data ,
2019-04-25 15:59:42 +02:00
res_ids [ i ] , val , extack ) ;
2018-03-27 18:22:00 -07:00
if ( err )
return err ;
}
}
return 0 ;
}
2019-04-25 15:59:43 +02:00
static const struct devlink_ops nsim_dev_devlink_ops = {
. reload = nsim_dev_reload ,
2018-03-27 18:22:00 -07:00
} ;
2019-04-25 15:59:49 +02:00
static struct nsim_dev * nsim_dev_create ( struct nsim_bus_dev * nsim_bus_dev )
2018-03-27 18:22:00 -07:00
{
2019-04-25 15:59:43 +02:00
struct nsim_dev * nsim_dev ;
2018-03-27 18:22:00 -07:00
struct devlink * devlink ;
2018-03-30 09:28:51 -07:00
int err ;
2018-03-27 18:22:00 -07:00
2019-04-25 15:59:43 +02:00
devlink = devlink_alloc ( & nsim_dev_devlink_ops , sizeof ( * nsim_dev ) ) ;
2018-03-27 18:22:00 -07:00
if ( ! devlink )
2019-04-25 15:59:49 +02:00
return ERR_PTR ( - ENOMEM ) ;
2019-04-25 15:59:43 +02:00
nsim_dev = devlink_priv ( devlink ) ;
2019-04-25 15:59:50 +02:00
nsim_dev - > nsim_bus_dev = nsim_bus_dev ;
2019-04-25 15:59:51 +02:00
nsim_dev - > switch_id . id_len = sizeof ( nsim_dev - > switch_id . id ) ;
get_random_bytes ( nsim_dev - > switch_id . id , nsim_dev - > switch_id . id_len ) ;
2018-03-27 18:22:00 -07:00
2019-04-25 15:59:43 +02:00
nsim_dev - > fib_data = nsim_fib_create ( ) ;
if ( IS_ERR ( nsim_dev - > fib_data ) ) {
err = PTR_ERR ( nsim_dev - > fib_data ) ;
2018-03-27 18:22:00 -07:00
goto err_devlink_free ;
2019-04-25 15:59:42 +02:00
}
2018-03-27 18:22:00 -07:00
2019-04-25 15:59:43 +02:00
err = nsim_dev_resources_register ( devlink ) ;
2018-03-27 18:22:00 -07:00
if ( err )
2019-04-25 15:59:42 +02:00
goto err_fib_destroy ;
2018-03-27 18:22:00 -07:00
2019-04-25 15:59:49 +02:00
err = devlink_register ( devlink , & nsim_bus_dev - > dev ) ;
2019-04-25 15:59:42 +02:00
if ( err )
goto err_resources_unregister ;
2018-03-27 18:22:00 -07:00
2019-04-25 15:59:50 +02:00
err = nsim_dev_debugfs_init ( nsim_dev ) ;
if ( err )
goto err_dl_unregister ;
err = nsim_bpf_dev_init ( nsim_dev ) ;
if ( err )
goto err_debugfs_exit ;
2019-04-25 15:59:49 +02:00
return nsim_dev ;
2018-03-27 18:22:00 -07:00
2019-04-25 15:59:50 +02:00
err_debugfs_exit :
nsim_dev_debugfs_exit ( nsim_dev ) ;
err_dl_unregister :
devlink_unregister ( devlink ) ;
2019-04-25 15:59:42 +02:00
err_resources_unregister :
devlink_resources_unregister ( devlink , NULL ) ;
err_fib_destroy :
2019-04-25 15:59:43 +02:00
nsim_fib_destroy ( nsim_dev - > fib_data ) ;
2018-03-27 18:22:00 -07:00
err_devlink_free :
devlink_free ( devlink ) ;
2019-04-25 15:59:49 +02:00
return ERR_PTR ( err ) ;
2018-03-27 18:22:00 -07:00
}
2019-04-25 15:59:49 +02:00
struct nsim_dev *
nsim_dev_create_with_ns ( struct nsim_bus_dev * nsim_bus_dev ,
struct netdevsim * ns )
2018-03-27 18:22:00 -07:00
{
2019-04-25 15:59:49 +02:00
struct nsim_dev * nsim_dev ;
2018-03-27 18:22:00 -07:00
2019-04-25 15:59:42 +02:00
dev_hold ( ns - > netdev ) ;
rtnl_unlock ( ) ;
2019-04-25 15:59:49 +02:00
nsim_dev = nsim_dev_create ( nsim_bus_dev ) ;
2019-04-25 15:59:42 +02:00
rtnl_lock ( ) ;
dev_put ( ns - > netdev ) ;
2019-04-25 15:59:49 +02:00
return nsim_dev ;
2018-03-27 18:22:00 -07:00
}
2019-04-25 15:59:49 +02:00
void nsim_dev_destroy ( struct nsim_dev * nsim_dev )
2018-03-27 18:22:00 -07:00
{
2019-04-25 15:59:49 +02:00
struct devlink * devlink = priv_to_devlink ( nsim_dev ) ;
2018-03-27 18:22:00 -07:00
2019-04-25 15:59:50 +02:00
nsim_bpf_dev_exit ( nsim_dev ) ;
nsim_dev_debugfs_exit ( nsim_dev ) ;
2019-04-25 15:59:42 +02:00
devlink_unregister ( devlink ) ;
devlink_resources_unregister ( devlink , NULL ) ;
2019-04-25 15:59:43 +02:00
nsim_fib_destroy ( nsim_dev - > fib_data ) ;
2019-04-25 15:59:42 +02:00
devlink_free ( devlink ) ;
2018-03-27 18:22:00 -07:00
}
2019-04-25 15:59:50 +02:00
int nsim_dev_init ( void )
{
2019-04-25 15:59:52 +02:00
nsim_dev_ddir = debugfs_create_dir ( DRV_NAME , NULL ) ;
2019-04-25 15:59:50 +02:00
if ( IS_ERR_OR_NULL ( nsim_dev_ddir ) )
return - ENOMEM ;
return 0 ;
}
void nsim_dev_exit ( void )
{
debugfs_remove_recursive ( nsim_dev_ddir ) ;
}