2018-03-28 04:22:00 +03:00
/*
* Copyright ( c ) 2018 Cumulus Networks . All rights reserved .
* Copyright ( c ) 2018 David Ahern < dsa @ cumulusnetworks . com >
*
* 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:42 +03:00
struct nsim_devlink {
struct nsim_fib_data * fib_data ;
} ;
2018-03-28 04:22:00 +03:00
/* IPv4
*/
2018-04-05 23:13:21 +03:00
static u64 nsim_ipv4_fib_resource_occ_get ( void * priv )
2018-03-28 04:22:00 +03:00
{
2019-04-25 16:59:42 +03:00
struct nsim_devlink * nsim_devlink = priv ;
2018-03-28 04:22:00 +03:00
2019-04-25 16:59:42 +03:00
return nsim_fib_get_val ( nsim_devlink - > fib_data ,
NSIM_RESOURCE_IPV4_FIB , false ) ;
2018-03-28 04:22:00 +03:00
}
2018-04-05 23:13:21 +03:00
static u64 nsim_ipv4_fib_rules_res_occ_get ( void * priv )
2018-03-28 04:22:00 +03:00
{
2019-04-25 16:59:42 +03:00
struct nsim_devlink * nsim_devlink = priv ;
2018-03-28 04:22:00 +03:00
2019-04-25 16:59:42 +03:00
return nsim_fib_get_val ( nsim_devlink - > fib_data ,
NSIM_RESOURCE_IPV4_FIB_RULES , false ) ;
2018-03-28 04:22:00 +03:00
}
/* IPv6
*/
2018-04-05 23:13:21 +03:00
static u64 nsim_ipv6_fib_resource_occ_get ( void * priv )
2018-03-28 04:22:00 +03:00
{
2019-04-25 16:59:42 +03:00
struct nsim_devlink * nsim_devlink = priv ;
2018-03-28 04:22:00 +03:00
2019-04-25 16:59:42 +03:00
return nsim_fib_get_val ( nsim_devlink - > fib_data ,
NSIM_RESOURCE_IPV6_FIB , false ) ;
2018-03-28 04:22:00 +03:00
}
2018-04-05 23:13:21 +03:00
static u64 nsim_ipv6_fib_rules_res_occ_get ( void * priv )
2018-03-28 04:22:00 +03:00
{
2019-04-25 16:59:42 +03:00
struct nsim_devlink * nsim_devlink = priv ;
2018-03-28 04:22:00 +03:00
2019-04-25 16:59:42 +03:00
return nsim_fib_get_val ( nsim_devlink - > fib_data ,
NSIM_RESOURCE_IPV6_FIB_RULES , false ) ;
2018-03-28 04:22:00 +03:00
}
static int devlink_resources_register ( struct devlink * devlink )
{
2019-04-25 16:59:42 +03:00
struct nsim_devlink * nsim_devlink = 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:42 +03:00
n = nsim_fib_get_val ( nsim_devlink - > fib_data ,
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:42 +03:00
n = nsim_fib_get_val ( nsim_devlink - > fib_data ,
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:42 +03:00
n = nsim_fib_get_val ( nsim_devlink - > fib_data ,
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:42 +03:00
n = nsim_fib_get_val ( nsim_devlink - > fib_data ,
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 ,
nsim_ipv4_fib_resource_occ_get ,
2019-04-25 16:59:42 +03:00
nsim_devlink ) ;
2018-04-05 23:13:21 +03:00
devlink_resource_occ_get_register ( devlink ,
NSIM_RESOURCE_IPV4_FIB_RULES ,
nsim_ipv4_fib_rules_res_occ_get ,
2019-04-25 16:59:42 +03:00
nsim_devlink ) ;
2018-04-05 23:13:21 +03:00
devlink_resource_occ_get_register ( devlink ,
NSIM_RESOURCE_IPV6_FIB ,
nsim_ipv6_fib_resource_occ_get ,
2019-04-25 16:59:42 +03:00
nsim_devlink ) ;
2018-04-05 23:13:21 +03:00
devlink_resource_occ_get_register ( devlink ,
NSIM_RESOURCE_IPV6_FIB_RULES ,
nsim_ipv6_fib_rules_res_occ_get ,
2019-04-25 16:59:42 +03:00
nsim_devlink ) ;
2018-03-28 04:22:00 +03:00
out :
return err ;
}
2018-06-05 18:14:09 +03:00
static int nsim_devlink_reload ( struct devlink * devlink ,
struct netlink_ext_ack * extack )
2018-03-28 04:22:00 +03:00
{
2019-04-25 16:59:42 +03:00
struct nsim_devlink * nsim_devlink = 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:42 +03:00
err = nsim_fib_set_max ( nsim_devlink - > fib_data ,
res_ids [ i ] , val , extack ) ;
2018-03-28 04:22:00 +03:00
if ( err )
return err ;
}
}
return 0 ;
}
static const struct devlink_ops nsim_devlink_ops = {
. reload = nsim_devlink_reload ,
} ;
2019-04-25 16:59:42 +03:00
static int __nsim_devlink_init ( struct netdevsim * ns )
2018-03-28 04:22:00 +03:00
{
2019-04-25 16:59:42 +03:00
struct nsim_devlink * nsim_devlink ;
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:42 +03:00
devlink = devlink_alloc ( & nsim_devlink_ops , sizeof ( * nsim_devlink ) ) ;
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:42 +03:00
nsim_devlink = devlink_priv ( devlink ) ;
2018-03-28 04:22:00 +03:00
2019-04-25 16:59:42 +03:00
nsim_devlink - > fib_data = nsim_fib_create ( ) ;
if ( IS_ERR ( nsim_devlink - > fib_data ) ) {
err = PTR_ERR ( nsim_devlink - > 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
err = devlink_resources_register ( devlink ) ;
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:42 +03:00
err = devlink_register ( devlink , & ns - > dev ) ;
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 :
nsim_fib_destroy ( nsim_devlink - > 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:42 +03:00
int nsim_devlink_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 ( ) ;
err = __nsim_devlink_init ( ns ) ;
rtnl_lock ( ) ;
dev_put ( ns - > netdev ) ;
return err ;
2018-03-28 04:22:00 +03:00
}
2019-04-25 16:59:42 +03:00
void nsim_devlink_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 ;
struct nsim_devlink * nsim_devlink = 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 ) ;
nsim_fib_destroy ( nsim_devlink - > fib_data ) ;
devlink_free ( devlink ) ;
2018-03-28 04:22:00 +03:00
}