2018-03-28 04:22:00 +03:00
/*
* Copyright ( c ) 2018 Cumulus Networks . All rights reserved .
* Copyright ( c ) 2018 David Ahern < dsa @ cumulusnetworks . com >
2019-04-25 16:59:43 +03:00
* Copyright ( c ) 2019 Mellanox Technologies . All rights reserved .
2018-03-28 04:22:00 +03: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 .
*/
# include <linux/device.h>
2019-04-25 16:59:42 +03:00
# include <linux/rtnetlink.h>
2018-03-28 04:22:00 +03:00
# include <net/devlink.h>
# include "netdevsim.h"
2019-04-25 16:59:43 +03:00
struct nsim_dev {
2019-04-25 16:59:42 +03:00
struct nsim_fib_data * fib_data ;
} ;
2018-03-28 04:22:00 +03:00
2019-04-25 16:59:43 +03:00
static u64 nsim_dev_ipv4_fib_resource_occ_get ( void * priv )
2018-03-28 04:22:00 +03:00
{
2019-04-25 16:59:43 +03:00
struct nsim_dev * nsim_dev = priv ;
2018-03-28 04:22:00 +03:00
2019-04-25 16:59:43 +03:00
return nsim_fib_get_val ( nsim_dev - > fib_data ,
2019-04-25 16:59:42 +03:00
NSIM_RESOURCE_IPV4_FIB , false ) ;
2018-03-28 04:22:00 +03:00
}
2019-04-25 16:59:43 +03:00
static u64 nsim_dev_ipv4_fib_rules_res_occ_get ( void * priv )
2018-03-28 04:22:00 +03:00
{
2019-04-25 16:59:43 +03:00
struct nsim_dev * nsim_dev = priv ;
2018-03-28 04:22:00 +03:00
2019-04-25 16:59:43 +03:00
return nsim_fib_get_val ( nsim_dev - > fib_data ,
2019-04-25 16:59:42 +03:00
NSIM_RESOURCE_IPV4_FIB_RULES , false ) ;
2018-03-28 04:22:00 +03:00
}
2019-04-25 16:59:43 +03:00
static u64 nsim_dev_ipv6_fib_resource_occ_get ( void * priv )
2018-03-28 04:22:00 +03:00
{
2019-04-25 16:59:43 +03:00
struct nsim_dev * nsim_dev = priv ;
2018-03-28 04:22:00 +03:00
2019-04-25 16:59:43 +03:00
return nsim_fib_get_val ( nsim_dev - > fib_data ,
2019-04-25 16:59:42 +03:00
NSIM_RESOURCE_IPV6_FIB , false ) ;
2018-03-28 04:22:00 +03:00
}
2019-04-25 16:59:43 +03:00
static u64 nsim_dev_ipv6_fib_rules_res_occ_get ( void * priv )
2018-03-28 04:22:00 +03:00
{
2019-04-25 16:59:43 +03:00
struct nsim_dev * nsim_dev = priv ;
2018-03-28 04:22:00 +03:00
2019-04-25 16:59:43 +03:00
return nsim_fib_get_val ( nsim_dev - > fib_data ,
2019-04-25 16:59:42 +03:00
NSIM_RESOURCE_IPV6_FIB_RULES , false ) ;
2018-03-28 04:22:00 +03:00
}
2019-04-25 16:59:43 +03:00
static int nsim_dev_resources_register ( struct devlink * devlink )
2018-03-28 04:22:00 +03:00
{
2019-04-25 16:59:43 +03:00
struct nsim_dev * nsim_dev = devlink_priv ( devlink ) ;
2018-03-28 04:22:00 +03: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 23:13:21 +03:00
& params ) ;
2018-03-28 04:22:00 +03:00
if ( err ) {
pr_err ( " Failed to register IPv4 top resource \n " ) ;
goto out ;
}
2019-04-25 16:59:43 +03:00
n = nsim_fib_get_val ( nsim_dev - > fib_data ,
2019-04-25 16:59:42 +03:00
NSIM_RESOURCE_IPV4_FIB , true ) ;
2018-03-28 04:22:00 +03:00
err = devlink_resource_register ( devlink , " fib " , n ,
NSIM_RESOURCE_IPV4_FIB ,
2018-04-05 23:13:21 +03:00
NSIM_RESOURCE_IPV4 , & params ) ;
2018-03-28 04:22:00 +03:00
if ( err ) {
pr_err ( " Failed to register IPv4 FIB resource \n " ) ;
return err ;
}
2019-04-25 16:59:43 +03:00
n = nsim_fib_get_val ( nsim_dev - > fib_data ,
2019-04-25 16:59:42 +03:00
NSIM_RESOURCE_IPV4_FIB_RULES , true ) ;
2018-03-28 04:22:00 +03:00
err = devlink_resource_register ( devlink , " fib-rules " , n ,
NSIM_RESOURCE_IPV4_FIB_RULES ,
2018-04-05 23:13:21 +03:00
NSIM_RESOURCE_IPV4 , & params ) ;
2018-03-28 04:22:00 +03: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 23:13:21 +03:00
& params ) ;
2018-03-28 04:22:00 +03:00
if ( err ) {
pr_err ( " Failed to register IPv6 top resource \n " ) ;
goto out ;
}
2019-04-25 16:59:43 +03:00
n = nsim_fib_get_val ( nsim_dev - > fib_data ,
2019-04-25 16:59:42 +03:00
NSIM_RESOURCE_IPV6_FIB , true ) ;
2018-03-28 04:22:00 +03:00
err = devlink_resource_register ( devlink , " fib " , n ,
NSIM_RESOURCE_IPV6_FIB ,
2018-04-05 23:13:21 +03:00
NSIM_RESOURCE_IPV6 , & params ) ;
2018-03-28 04:22:00 +03:00
if ( err ) {
pr_err ( " Failed to register IPv6 FIB resource \n " ) ;
return err ;
}
2019-04-25 16:59:43 +03:00
n = nsim_fib_get_val ( nsim_dev - > fib_data ,
2019-04-25 16:59:42 +03:00
NSIM_RESOURCE_IPV6_FIB_RULES , true ) ;
2018-03-28 04:22:00 +03:00
err = devlink_resource_register ( devlink , " fib-rules " , n ,
NSIM_RESOURCE_IPV6_FIB_RULES ,
2018-04-05 23:13:21 +03:00
NSIM_RESOURCE_IPV6 , & params ) ;
2018-03-28 04:22:00 +03:00
if ( err ) {
pr_err ( " Failed to register IPv6 FIB rules resource \n " ) ;
return err ;
}
2018-04-05 23:13:21 +03:00
devlink_resource_occ_get_register ( devlink ,
NSIM_RESOURCE_IPV4_FIB ,
2019-04-25 16:59:43 +03:00
nsim_dev_ipv4_fib_resource_occ_get ,
nsim_dev ) ;
2018-04-05 23:13:21 +03:00
devlink_resource_occ_get_register ( devlink ,
NSIM_RESOURCE_IPV4_FIB_RULES ,
2019-04-25 16:59:43 +03:00
nsim_dev_ipv4_fib_rules_res_occ_get ,
nsim_dev ) ;
2018-04-05 23:13:21 +03:00
devlink_resource_occ_get_register ( devlink ,
NSIM_RESOURCE_IPV6_FIB ,
2019-04-25 16:59:43 +03:00
nsim_dev_ipv6_fib_resource_occ_get ,
nsim_dev ) ;
2018-04-05 23:13:21 +03:00
devlink_resource_occ_get_register ( devlink ,
NSIM_RESOURCE_IPV6_FIB_RULES ,
2019-04-25 16:59:43 +03:00
nsim_dev_ipv6_fib_rules_res_occ_get ,
nsim_dev ) ;
2018-03-28 04:22:00 +03:00
out :
return err ;
}
2019-04-25 16:59:43 +03:00
static int nsim_dev_reload ( struct devlink * devlink ,
struct netlink_ext_ack * extack )
2018-03-28 04:22:00 +03:00
{
2019-04-25 16:59:43 +03:00
struct nsim_dev * nsim_dev = devlink_priv ( devlink ) ;
2018-03-28 04:22:00 +03: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 16:59:43 +03:00
err = nsim_fib_set_max ( nsim_dev - > fib_data ,
2019-04-25 16:59:42 +03:00
res_ids [ i ] , val , extack ) ;
2018-03-28 04:22:00 +03:00
if ( err )
return err ;
}
}
return 0 ;
}
2019-04-25 16:59:43 +03:00
static const struct devlink_ops nsim_dev_devlink_ops = {
. reload = nsim_dev_reload ,
2018-03-28 04:22:00 +03:00
} ;
2019-04-25 16:59:43 +03:00
static int __nsim_dev_init ( struct netdevsim * ns )
2018-03-28 04:22:00 +03:00
{
2019-04-25 16:59:43 +03:00
struct nsim_dev * nsim_dev ;
2018-03-28 04:22:00 +03:00
struct devlink * devlink ;
2018-03-30 19:28:51 +03:00
int err ;
2018-03-28 04:22:00 +03:00
2019-04-25 16:59:43 +03:00
devlink = devlink_alloc ( & nsim_dev_devlink_ops , sizeof ( * nsim_dev ) ) ;
2018-03-28 04:22:00 +03:00
if ( ! devlink )
2018-03-30 19:28:51 +03:00
return - ENOMEM ;
2019-04-25 16:59:43 +03:00
nsim_dev = devlink_priv ( devlink ) ;
2018-03-28 04:22:00 +03:00
2019-04-25 16:59:43 +03:00
nsim_dev - > fib_data = nsim_fib_create ( ) ;
if ( IS_ERR ( nsim_dev - > fib_data ) ) {
err = PTR_ERR ( nsim_dev - > fib_data ) ;
2018-03-28 04:22:00 +03:00
goto err_devlink_free ;
2019-04-25 16:59:42 +03:00
}
2018-03-28 04:22:00 +03:00
2019-04-25 16:59:43 +03:00
err = nsim_dev_resources_register ( devlink ) ;
2018-03-28 04:22:00 +03:00
if ( err )
2019-04-25 16:59:42 +03:00
goto err_fib_destroy ;
2018-03-28 04:22:00 +03:00
2019-04-25 16:59:45 +03:00
err = devlink_register ( devlink , & ns - > nsim_bus_dev - > dev ) ;
2019-04-25 16:59:42 +03:00
if ( err )
goto err_resources_unregister ;
2018-03-28 04:22:00 +03:00
2019-04-25 16:59:42 +03:00
ns - > devlink = devlink ;
2018-03-28 04:22:00 +03:00
2018-03-30 19:28:51 +03:00
return 0 ;
2018-03-28 04:22:00 +03:00
2019-04-25 16:59:42 +03:00
err_resources_unregister :
devlink_resources_unregister ( devlink , NULL ) ;
err_fib_destroy :
2019-04-25 16:59:43 +03:00
nsim_fib_destroy ( nsim_dev - > fib_data ) ;
2018-03-28 04:22:00 +03:00
err_devlink_free :
devlink_free ( devlink ) ;
2018-03-30 19:28:51 +03:00
return err ;
2018-03-28 04:22:00 +03:00
}
2019-04-25 16:59:43 +03:00
int nsim_dev_init ( struct netdevsim * ns )
2018-03-28 04:22:00 +03:00
{
2019-04-25 16:59:42 +03:00
int err ;
2018-03-28 04:22:00 +03:00
2019-04-25 16:59:42 +03:00
dev_hold ( ns - > netdev ) ;
rtnl_unlock ( ) ;
2019-04-25 16:59:43 +03:00
err = __nsim_dev_init ( ns ) ;
2019-04-25 16:59:42 +03:00
rtnl_lock ( ) ;
dev_put ( ns - > netdev ) ;
return err ;
2018-03-28 04:22:00 +03:00
}
2019-04-25 16:59:43 +03:00
void nsim_dev_exit ( struct netdevsim * ns )
2018-03-28 04:22:00 +03:00
{
2019-04-25 16:59:42 +03:00
struct devlink * devlink = ns - > devlink ;
2019-04-25 16:59:43 +03:00
struct nsim_dev * nsim_dev = devlink_priv ( devlink ) ;
2018-03-28 04:22:00 +03:00
2019-04-25 16:59:42 +03:00
devlink_unregister ( devlink ) ;
devlink_resources_unregister ( devlink , NULL ) ;
2019-04-25 16:59:43 +03:00
nsim_fib_destroy ( nsim_dev - > fib_data ) ;
2019-04-25 16:59:42 +03:00
devlink_free ( devlink ) ;
2018-03-28 04:22:00 +03:00
}