2016-02-26 19:32:23 +03:00
/*
* net / core / devlink . c - Network physical / parent device Netlink interface
*
* Heavily inspired by net / wireless /
* Copyright ( c ) 2016 Mellanox Technologies . All rights reserved .
* Copyright ( c ) 2016 Jiri Pirko < jiri @ mellanox . com >
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*/
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/types.h>
# include <linux/slab.h>
# include <linux/gfp.h>
# include <linux/device.h>
# include <linux/list.h>
# include <linux/netdevice.h>
# include <rdma/ib_verbs.h>
# include <net/netlink.h>
# include <net/genetlink.h>
# include <net/rtnetlink.h>
# include <net/net_namespace.h>
# include <net/sock.h>
# include <net/devlink.h>
2016-07-12 19:05:03 +03:00
# define CREATE_TRACE_POINTS
# include <trace/events/devlink.h>
2017-08-24 09:39:59 +03:00
static struct devlink_dpipe_field devlink_dpipe_fields_ethernet [ ] = {
{
2017-08-31 03:07:30 +03:00
. name = " destination mac " ,
2017-08-24 09:39:59 +03:00
. 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 ( devlink_dpipe_header_ethernet ) ;
2017-08-24 09:40:00 +03:00
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 ( devlink_dpipe_header_ipv4 ) ;
2017-08-31 18:59:12 +03:00
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 ( devlink_dpipe_header_ipv6 ) ;
2016-07-12 19:05:03 +03:00
EXPORT_TRACEPOINT_SYMBOL_GPL ( devlink_hwmsg ) ;
2016-02-26 19:32:23 +03:00
static LIST_HEAD ( devlink_list ) ;
/* devlink_mutex
*
* An overall lock guarding every operation coming from userspace .
* It also guards devlink devices list and it is taken when
* driver registers / unregisters it .
*/
static DEFINE_MUTEX ( devlink_mutex ) ;
/* devlink_port_mutex
*
* Shared lock to guard lists of ports in all devlink devices .
*/
static DEFINE_MUTEX ( devlink_port_mutex ) ;
static struct net * devlink_net ( const struct devlink * devlink )
{
return read_pnet ( & devlink - > _net ) ;
}
static void devlink_net_set ( struct devlink * devlink , struct net * net )
{
write_pnet ( & devlink - > _net , net ) ;
}
static struct devlink * devlink_get_from_attrs ( struct net * net ,
struct nlattr * * attrs )
{
struct devlink * devlink ;
char * busname ;
char * devname ;
if ( ! attrs [ DEVLINK_ATTR_BUS_NAME ] | | ! attrs [ DEVLINK_ATTR_DEV_NAME ] )
return ERR_PTR ( - EINVAL ) ;
busname = nla_data ( attrs [ DEVLINK_ATTR_BUS_NAME ] ) ;
devname = nla_data ( attrs [ DEVLINK_ATTR_DEV_NAME ] ) ;
list_for_each_entry ( devlink , & devlink_list , list ) {
if ( strcmp ( devlink - > dev - > bus - > name , busname ) = = 0 & &
strcmp ( dev_name ( devlink - > dev ) , devname ) = = 0 & &
net_eq ( devlink_net ( devlink ) , net ) )
return devlink ;
}
return ERR_PTR ( - ENODEV ) ;
}
static struct devlink * devlink_get_from_info ( struct genl_info * info )
{
return devlink_get_from_attrs ( genl_info_net ( info ) , info - > attrs ) ;
}
static struct devlink_port * devlink_port_get_by_index ( struct devlink * devlink ,
int port_index )
{
struct devlink_port * devlink_port ;
list_for_each_entry ( devlink_port , & devlink - > port_list , list ) {
if ( devlink_port - > index = = port_index )
return devlink_port ;
}
return NULL ;
}
static bool devlink_port_index_exists ( struct devlink * devlink , int port_index )
{
return devlink_port_get_by_index ( devlink , port_index ) ;
}
static struct devlink_port * devlink_port_get_from_attrs ( struct devlink * devlink ,
struct nlattr * * attrs )
{
if ( attrs [ DEVLINK_ATTR_PORT_INDEX ] ) {
u32 port_index = nla_get_u32 ( attrs [ DEVLINK_ATTR_PORT_INDEX ] ) ;
struct devlink_port * devlink_port ;
devlink_port = devlink_port_get_by_index ( devlink , port_index ) ;
if ( ! devlink_port )
return ERR_PTR ( - ENODEV ) ;
return devlink_port ;
}
return ERR_PTR ( - EINVAL ) ;
}
static struct devlink_port * devlink_port_get_from_info ( struct devlink * devlink ,
struct genl_info * info )
{
return devlink_port_get_from_attrs ( devlink , info - > attrs ) ;
}
2016-04-14 19:19:13 +03:00
struct devlink_sb {
struct list_head list ;
unsigned int index ;
u32 size ;
u16 ingress_pools_count ;
u16 egress_pools_count ;
u16 ingress_tc_count ;
u16 egress_tc_count ;
} ;
static u16 devlink_sb_pool_count ( struct devlink_sb * devlink_sb )
{
return devlink_sb - > ingress_pools_count + devlink_sb - > egress_pools_count ;
}
static struct devlink_sb * devlink_sb_get_by_index ( struct devlink * devlink ,
unsigned int sb_index )
{
struct devlink_sb * devlink_sb ;
list_for_each_entry ( devlink_sb , & devlink - > sb_list , list ) {
if ( devlink_sb - > index = = sb_index )
return devlink_sb ;
}
return NULL ;
}
static bool devlink_sb_index_exists ( struct devlink * devlink ,
unsigned int sb_index )
{
return devlink_sb_get_by_index ( devlink , sb_index ) ;
}
static struct devlink_sb * devlink_sb_get_from_attrs ( struct devlink * devlink ,
struct nlattr * * attrs )
{
if ( attrs [ DEVLINK_ATTR_SB_INDEX ] ) {
u32 sb_index = nla_get_u32 ( attrs [ DEVLINK_ATTR_SB_INDEX ] ) ;
struct devlink_sb * devlink_sb ;
devlink_sb = devlink_sb_get_by_index ( devlink , sb_index ) ;
if ( ! devlink_sb )
return ERR_PTR ( - ENODEV ) ;
return devlink_sb ;
}
return ERR_PTR ( - EINVAL ) ;
}
static struct devlink_sb * devlink_sb_get_from_info ( struct devlink * devlink ,
struct genl_info * info )
{
return devlink_sb_get_from_attrs ( devlink , info - > attrs ) ;
}
static int devlink_sb_pool_index_get_from_attrs ( struct devlink_sb * devlink_sb ,
struct nlattr * * attrs ,
u16 * p_pool_index )
{
u16 val ;
if ( ! attrs [ DEVLINK_ATTR_SB_POOL_INDEX ] )
return - EINVAL ;
val = nla_get_u16 ( attrs [ DEVLINK_ATTR_SB_POOL_INDEX ] ) ;
if ( val > = devlink_sb_pool_count ( devlink_sb ) )
return - EINVAL ;
* p_pool_index = val ;
return 0 ;
}
static int devlink_sb_pool_index_get_from_info ( struct devlink_sb * devlink_sb ,
struct genl_info * info ,
u16 * p_pool_index )
{
return devlink_sb_pool_index_get_from_attrs ( devlink_sb , info - > attrs ,
p_pool_index ) ;
}
static int
devlink_sb_pool_type_get_from_attrs ( struct nlattr * * attrs ,
enum devlink_sb_pool_type * p_pool_type )
{
u8 val ;
if ( ! attrs [ DEVLINK_ATTR_SB_POOL_TYPE ] )
return - EINVAL ;
val = nla_get_u8 ( attrs [ DEVLINK_ATTR_SB_POOL_TYPE ] ) ;
if ( val ! = DEVLINK_SB_POOL_TYPE_INGRESS & &
val ! = DEVLINK_SB_POOL_TYPE_EGRESS )
return - EINVAL ;
* p_pool_type = val ;
return 0 ;
}
static int
devlink_sb_pool_type_get_from_info ( struct genl_info * info ,
enum devlink_sb_pool_type * p_pool_type )
{
return devlink_sb_pool_type_get_from_attrs ( info - > attrs , p_pool_type ) ;
}
static int
devlink_sb_th_type_get_from_attrs ( struct nlattr * * attrs ,
enum devlink_sb_threshold_type * p_th_type )
{
u8 val ;
if ( ! attrs [ DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE ] )
return - EINVAL ;
val = nla_get_u8 ( attrs [ DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE ] ) ;
if ( val ! = DEVLINK_SB_THRESHOLD_TYPE_STATIC & &
val ! = DEVLINK_SB_THRESHOLD_TYPE_DYNAMIC )
return - EINVAL ;
* p_th_type = val ;
return 0 ;
}
static int
devlink_sb_th_type_get_from_info ( struct genl_info * info ,
enum devlink_sb_threshold_type * p_th_type )
{
return devlink_sb_th_type_get_from_attrs ( info - > attrs , p_th_type ) ;
}
static int
devlink_sb_tc_index_get_from_attrs ( struct devlink_sb * devlink_sb ,
struct nlattr * * attrs ,
enum devlink_sb_pool_type pool_type ,
u16 * p_tc_index )
{
u16 val ;
if ( ! attrs [ DEVLINK_ATTR_SB_TC_INDEX ] )
return - EINVAL ;
val = nla_get_u16 ( attrs [ DEVLINK_ATTR_SB_TC_INDEX ] ) ;
if ( pool_type = = DEVLINK_SB_POOL_TYPE_INGRESS & &
val > = devlink_sb - > ingress_tc_count )
return - EINVAL ;
if ( pool_type = = DEVLINK_SB_POOL_TYPE_EGRESS & &
val > = devlink_sb - > egress_tc_count )
return - EINVAL ;
* p_tc_index = val ;
return 0 ;
}
static int
devlink_sb_tc_index_get_from_info ( struct devlink_sb * devlink_sb ,
struct genl_info * info ,
enum devlink_sb_pool_type pool_type ,
u16 * p_tc_index )
{
return devlink_sb_tc_index_get_from_attrs ( devlink_sb , info - > attrs ,
pool_type , p_tc_index ) ;
}
2016-04-08 20:12:48 +03:00
# define DEVLINK_NL_FLAG_NEED_DEVLINK BIT(0)
# define DEVLINK_NL_FLAG_NEED_PORT BIT(1)
2016-04-14 19:19:13 +03:00
# define DEVLINK_NL_FLAG_NEED_SB BIT(2)
2016-04-14 19:19:14 +03:00
# define DEVLINK_NL_FLAG_LOCK_PORTS BIT(3)
/* port is not needed but we need to ensure they don't
* change in the middle of command
*/
2016-02-26 19:32:23 +03:00
static int devlink_nl_pre_doit ( const struct genl_ops * ops ,
struct sk_buff * skb , struct genl_info * info )
{
struct devlink * devlink ;
mutex_lock ( & devlink_mutex ) ;
devlink = devlink_get_from_info ( info ) ;
if ( IS_ERR ( devlink ) ) {
mutex_unlock ( & devlink_mutex ) ;
return PTR_ERR ( devlink ) ;
}
2016-04-08 20:12:48 +03:00
if ( ops - > internal_flags & DEVLINK_NL_FLAG_NEED_DEVLINK ) {
info - > user_ptr [ 0 ] = devlink ;
} else if ( ops - > internal_flags & DEVLINK_NL_FLAG_NEED_PORT ) {
2016-02-26 19:32:23 +03:00
struct devlink_port * devlink_port ;
mutex_lock ( & devlink_port_mutex ) ;
devlink_port = devlink_port_get_from_info ( devlink , info ) ;
if ( IS_ERR ( devlink_port ) ) {
mutex_unlock ( & devlink_port_mutex ) ;
mutex_unlock ( & devlink_mutex ) ;
return PTR_ERR ( devlink_port ) ;
}
2016-04-08 20:12:48 +03:00
info - > user_ptr [ 0 ] = devlink_port ;
2016-02-26 19:32:23 +03:00
}
2016-04-14 19:19:14 +03:00
if ( ops - > internal_flags & DEVLINK_NL_FLAG_LOCK_PORTS ) {
mutex_lock ( & devlink_port_mutex ) ;
}
2016-04-14 19:19:13 +03:00
if ( ops - > internal_flags & DEVLINK_NL_FLAG_NEED_SB ) {
struct devlink_sb * devlink_sb ;
devlink_sb = devlink_sb_get_from_info ( devlink , info ) ;
if ( IS_ERR ( devlink_sb ) ) {
if ( ops - > internal_flags & DEVLINK_NL_FLAG_NEED_PORT )
mutex_unlock ( & devlink_port_mutex ) ;
mutex_unlock ( & devlink_mutex ) ;
return PTR_ERR ( devlink_sb ) ;
}
info - > user_ptr [ 1 ] = devlink_sb ;
}
2016-02-26 19:32:23 +03:00
return 0 ;
}
static void devlink_nl_post_doit ( const struct genl_ops * ops ,
struct sk_buff * skb , struct genl_info * info )
{
2016-04-14 19:19:14 +03:00
if ( ops - > internal_flags & DEVLINK_NL_FLAG_NEED_PORT | |
ops - > internal_flags & DEVLINK_NL_FLAG_LOCK_PORTS )
2016-02-26 19:32:23 +03:00
mutex_unlock ( & devlink_port_mutex ) ;
mutex_unlock ( & devlink_mutex ) ;
}
2016-10-24 15:40:03 +03:00
static struct genl_family devlink_nl_family ;
2016-02-26 19:32:23 +03:00
enum devlink_multicast_groups {
DEVLINK_MCGRP_CONFIG ,
} ;
static const struct genl_multicast_group devlink_nl_mcgrps [ ] = {
[ DEVLINK_MCGRP_CONFIG ] = { . name = DEVLINK_GENL_MCGRP_CONFIG_NAME } ,
} ;
static int devlink_nl_put_handle ( struct sk_buff * msg , struct devlink * devlink )
{
if ( nla_put_string ( msg , DEVLINK_ATTR_BUS_NAME , devlink - > dev - > bus - > name ) )
return - EMSGSIZE ;
if ( nla_put_string ( msg , DEVLINK_ATTR_DEV_NAME , dev_name ( devlink - > dev ) ) )
return - EMSGSIZE ;
return 0 ;
}
static int devlink_nl_fill ( struct sk_buff * msg , struct devlink * devlink ,
enum devlink_command cmd , u32 portid ,
u32 seq , int flags )
{
void * hdr ;
hdr = genlmsg_put ( msg , portid , seq , & devlink_nl_family , flags , cmd ) ;
if ( ! hdr )
return - EMSGSIZE ;
if ( devlink_nl_put_handle ( msg , devlink ) )
goto nla_put_failure ;
genlmsg_end ( msg , hdr ) ;
return 0 ;
nla_put_failure :
genlmsg_cancel ( msg , hdr ) ;
return - EMSGSIZE ;
}
static void devlink_notify ( struct devlink * devlink , enum devlink_command cmd )
{
struct sk_buff * msg ;
int err ;
WARN_ON ( cmd ! = DEVLINK_CMD_NEW & & cmd ! = DEVLINK_CMD_DEL ) ;
msg = nlmsg_new ( NLMSG_DEFAULT_SIZE , GFP_KERNEL ) ;
if ( ! msg )
return ;
err = devlink_nl_fill ( msg , devlink , cmd , 0 , 0 , 0 ) ;
if ( err ) {
nlmsg_free ( msg ) ;
return ;
}
genlmsg_multicast_netns ( & devlink_nl_family , devlink_net ( devlink ) ,
msg , 0 , DEVLINK_MCGRP_CONFIG , GFP_KERNEL ) ;
}
static int devlink_nl_port_fill ( struct sk_buff * msg , struct devlink * devlink ,
struct devlink_port * devlink_port ,
enum devlink_command cmd , u32 portid ,
u32 seq , int flags )
{
void * hdr ;
hdr = genlmsg_put ( msg , portid , seq , & devlink_nl_family , flags , cmd ) ;
if ( ! hdr )
return - EMSGSIZE ;
if ( devlink_nl_put_handle ( msg , devlink ) )
goto nla_put_failure ;
if ( nla_put_u32 ( msg , DEVLINK_ATTR_PORT_INDEX , devlink_port - > index ) )
goto nla_put_failure ;
if ( nla_put_u16 ( msg , DEVLINK_ATTR_PORT_TYPE , devlink_port - > type ) )
goto nla_put_failure ;
if ( devlink_port - > desired_type ! = DEVLINK_PORT_TYPE_NOTSET & &
nla_put_u16 ( msg , DEVLINK_ATTR_PORT_DESIRED_TYPE ,
devlink_port - > desired_type ) )
goto nla_put_failure ;
if ( devlink_port - > type = = DEVLINK_PORT_TYPE_ETH ) {
struct net_device * netdev = devlink_port - > type_dev ;
if ( netdev & &
( nla_put_u32 ( msg , DEVLINK_ATTR_PORT_NETDEV_IFINDEX ,
netdev - > ifindex ) | |
nla_put_string ( msg , DEVLINK_ATTR_PORT_NETDEV_NAME ,
netdev - > name ) ) )
goto nla_put_failure ;
}
if ( devlink_port - > type = = DEVLINK_PORT_TYPE_IB ) {
struct ib_device * ibdev = devlink_port - > type_dev ;
if ( ibdev & &
nla_put_string ( msg , DEVLINK_ATTR_PORT_IBDEV_NAME ,
ibdev - > name ) )
goto nla_put_failure ;
}
if ( devlink_port - > split & &
nla_put_u32 ( msg , DEVLINK_ATTR_PORT_SPLIT_GROUP ,
devlink_port - > split_group ) )
goto nla_put_failure ;
genlmsg_end ( msg , hdr ) ;
return 0 ;
nla_put_failure :
genlmsg_cancel ( msg , hdr ) ;
return - EMSGSIZE ;
}
static void devlink_port_notify ( struct devlink_port * devlink_port ,
enum devlink_command cmd )
{
struct devlink * devlink = devlink_port - > devlink ;
struct sk_buff * msg ;
int err ;
if ( ! devlink_port - > registered )
return ;
WARN_ON ( cmd ! = DEVLINK_CMD_PORT_NEW & & cmd ! = DEVLINK_CMD_PORT_DEL ) ;
msg = nlmsg_new ( NLMSG_DEFAULT_SIZE , GFP_KERNEL ) ;
if ( ! msg )
return ;
err = devlink_nl_port_fill ( msg , devlink , devlink_port , cmd , 0 , 0 , 0 ) ;
if ( err ) {
nlmsg_free ( msg ) ;
return ;
}
genlmsg_multicast_netns ( & devlink_nl_family , devlink_net ( devlink ) ,
msg , 0 , DEVLINK_MCGRP_CONFIG , GFP_KERNEL ) ;
}
static int devlink_nl_cmd_get_doit ( struct sk_buff * skb , struct genl_info * info )
{
struct devlink * devlink = info - > user_ptr [ 0 ] ;
struct sk_buff * msg ;
int err ;
msg = nlmsg_new ( NLMSG_DEFAULT_SIZE , GFP_KERNEL ) ;
if ( ! msg )
return - ENOMEM ;
err = devlink_nl_fill ( msg , devlink , DEVLINK_CMD_NEW ,
info - > snd_portid , info - > snd_seq , 0 ) ;
if ( err ) {
nlmsg_free ( msg ) ;
return err ;
}
return genlmsg_reply ( msg , info ) ;
}
static int devlink_nl_cmd_get_dumpit ( struct sk_buff * msg ,
struct netlink_callback * cb )
{
struct devlink * devlink ;
int start = cb - > args [ 0 ] ;
int idx = 0 ;
int err ;
mutex_lock ( & devlink_mutex ) ;
list_for_each_entry ( devlink , & devlink_list , list ) {
if ( ! net_eq ( devlink_net ( devlink ) , sock_net ( msg - > sk ) ) )
continue ;
if ( idx < start ) {
idx + + ;
continue ;
}
err = devlink_nl_fill ( msg , devlink , DEVLINK_CMD_NEW ,
NETLINK_CB ( cb - > skb ) . portid ,
cb - > nlh - > nlmsg_seq , NLM_F_MULTI ) ;
if ( err )
goto out ;
idx + + ;
}
out :
mutex_unlock ( & devlink_mutex ) ;
cb - > args [ 0 ] = idx ;
return msg - > len ;
}
static int devlink_nl_cmd_port_get_doit ( struct sk_buff * skb ,
struct genl_info * info )
{
2016-04-08 20:12:48 +03:00
struct devlink_port * devlink_port = info - > user_ptr [ 0 ] ;
struct devlink * devlink = devlink_port - > devlink ;
2016-02-26 19:32:23 +03:00
struct sk_buff * msg ;
int err ;
msg = nlmsg_new ( NLMSG_DEFAULT_SIZE , GFP_KERNEL ) ;
if ( ! msg )
return - ENOMEM ;
err = devlink_nl_port_fill ( msg , devlink , devlink_port ,
DEVLINK_CMD_PORT_NEW ,
info - > snd_portid , info - > snd_seq , 0 ) ;
if ( err ) {
nlmsg_free ( msg ) ;
return err ;
}
return genlmsg_reply ( msg , info ) ;
}
static int devlink_nl_cmd_port_get_dumpit ( struct sk_buff * msg ,
struct netlink_callback * cb )
{
struct devlink * devlink ;
struct devlink_port * devlink_port ;
int start = cb - > args [ 0 ] ;
int idx = 0 ;
int err ;
mutex_lock ( & devlink_mutex ) ;
mutex_lock ( & devlink_port_mutex ) ;
list_for_each_entry ( devlink , & devlink_list , list ) {
if ( ! net_eq ( devlink_net ( devlink ) , sock_net ( msg - > sk ) ) )
continue ;
list_for_each_entry ( devlink_port , & devlink - > port_list , list ) {
if ( idx < start ) {
idx + + ;
continue ;
}
err = devlink_nl_port_fill ( msg , devlink , devlink_port ,
DEVLINK_CMD_NEW ,
NETLINK_CB ( cb - > skb ) . portid ,
cb - > nlh - > nlmsg_seq ,
NLM_F_MULTI ) ;
if ( err )
goto out ;
idx + + ;
}
}
out :
mutex_unlock ( & devlink_port_mutex ) ;
mutex_unlock ( & devlink_mutex ) ;
cb - > args [ 0 ] = idx ;
return msg - > len ;
}
static int devlink_port_type_set ( struct devlink * devlink ,
struct devlink_port * devlink_port ,
enum devlink_port_type port_type )
{
int err ;
if ( devlink - > ops & & devlink - > ops - > port_type_set ) {
if ( port_type = = DEVLINK_PORT_TYPE_NOTSET )
return - EINVAL ;
2016-10-23 18:43:05 +03:00
if ( port_type = = devlink_port - > type )
return 0 ;
2016-02-26 19:32:23 +03:00
err = devlink - > ops - > port_type_set ( devlink_port , port_type ) ;
if ( err )
return err ;
devlink_port - > desired_type = port_type ;
devlink_port_notify ( devlink_port , DEVLINK_CMD_PORT_NEW ) ;
return 0 ;
}
return - EOPNOTSUPP ;
}
static int devlink_nl_cmd_port_set_doit ( struct sk_buff * skb ,
struct genl_info * info )
{
2016-04-08 20:12:48 +03:00
struct devlink_port * devlink_port = info - > user_ptr [ 0 ] ;
struct devlink * devlink = devlink_port - > devlink ;
2016-02-26 19:32:23 +03:00
int err ;
if ( info - > attrs [ DEVLINK_ATTR_PORT_TYPE ] ) {
enum devlink_port_type port_type ;
port_type = nla_get_u16 ( info - > attrs [ DEVLINK_ATTR_PORT_TYPE ] ) ;
err = devlink_port_type_set ( devlink , devlink_port , port_type ) ;
if ( err )
return err ;
}
return 0 ;
}
static int devlink_port_split ( struct devlink * devlink ,
u32 port_index , u32 count )
{
if ( devlink - > ops & & devlink - > ops - > port_split )
return devlink - > ops - > port_split ( devlink , port_index , count ) ;
return - EOPNOTSUPP ;
}
static int devlink_nl_cmd_port_split_doit ( struct sk_buff * skb ,
struct genl_info * info )
{
struct devlink * devlink = info - > user_ptr [ 0 ] ;
u32 port_index ;
u32 count ;
if ( ! info - > attrs [ DEVLINK_ATTR_PORT_INDEX ] | |
! info - > attrs [ DEVLINK_ATTR_PORT_SPLIT_COUNT ] )
return - EINVAL ;
port_index = nla_get_u32 ( info - > attrs [ DEVLINK_ATTR_PORT_INDEX ] ) ;
count = nla_get_u32 ( info - > attrs [ DEVLINK_ATTR_PORT_SPLIT_COUNT ] ) ;
return devlink_port_split ( devlink , port_index , count ) ;
}
static int devlink_port_unsplit ( struct devlink * devlink , u32 port_index )
{
if ( devlink - > ops & & devlink - > ops - > port_unsplit )
return devlink - > ops - > port_unsplit ( devlink , port_index ) ;
return - EOPNOTSUPP ;
}
static int devlink_nl_cmd_port_unsplit_doit ( struct sk_buff * skb ,
struct genl_info * info )
{
struct devlink * devlink = info - > user_ptr [ 0 ] ;
u32 port_index ;
if ( ! info - > attrs [ DEVLINK_ATTR_PORT_INDEX ] )
return - EINVAL ;
port_index = nla_get_u32 ( info - > attrs [ DEVLINK_ATTR_PORT_INDEX ] ) ;
return devlink_port_unsplit ( devlink , port_index ) ;
}
2016-04-14 19:19:13 +03:00
static int devlink_nl_sb_fill ( struct sk_buff * msg , struct devlink * devlink ,
struct devlink_sb * devlink_sb ,
enum devlink_command cmd , u32 portid ,
u32 seq , int flags )
{
void * hdr ;
hdr = genlmsg_put ( msg , portid , seq , & devlink_nl_family , flags , cmd ) ;
if ( ! hdr )
return - EMSGSIZE ;
if ( devlink_nl_put_handle ( msg , devlink ) )
goto nla_put_failure ;
if ( nla_put_u32 ( msg , DEVLINK_ATTR_SB_INDEX , devlink_sb - > index ) )
goto nla_put_failure ;
if ( nla_put_u32 ( msg , DEVLINK_ATTR_SB_SIZE , devlink_sb - > size ) )
goto nla_put_failure ;
if ( nla_put_u16 ( msg , DEVLINK_ATTR_SB_INGRESS_POOL_COUNT ,
devlink_sb - > ingress_pools_count ) )
goto nla_put_failure ;
if ( nla_put_u16 ( msg , DEVLINK_ATTR_SB_EGRESS_POOL_COUNT ,
devlink_sb - > egress_pools_count ) )
goto nla_put_failure ;
if ( nla_put_u16 ( msg , DEVLINK_ATTR_SB_INGRESS_TC_COUNT ,
devlink_sb - > ingress_tc_count ) )
goto nla_put_failure ;
if ( nla_put_u16 ( msg , DEVLINK_ATTR_SB_EGRESS_TC_COUNT ,
devlink_sb - > egress_tc_count ) )
goto nla_put_failure ;
genlmsg_end ( msg , hdr ) ;
return 0 ;
nla_put_failure :
genlmsg_cancel ( msg , hdr ) ;
return - EMSGSIZE ;
}
static int devlink_nl_cmd_sb_get_doit ( struct sk_buff * skb ,
struct genl_info * info )
{
struct devlink * devlink = info - > user_ptr [ 0 ] ;
struct devlink_sb * devlink_sb = info - > user_ptr [ 1 ] ;
struct sk_buff * msg ;
int err ;
msg = nlmsg_new ( NLMSG_DEFAULT_SIZE , GFP_KERNEL ) ;
if ( ! msg )
return - ENOMEM ;
err = devlink_nl_sb_fill ( msg , devlink , devlink_sb ,
DEVLINK_CMD_SB_NEW ,
info - > snd_portid , info - > snd_seq , 0 ) ;
if ( err ) {
nlmsg_free ( msg ) ;
return err ;
}
return genlmsg_reply ( msg , info ) ;
}
static int devlink_nl_cmd_sb_get_dumpit ( struct sk_buff * msg ,
struct netlink_callback * cb )
{
struct devlink * devlink ;
struct devlink_sb * devlink_sb ;
int start = cb - > args [ 0 ] ;
int idx = 0 ;
int err ;
mutex_lock ( & devlink_mutex ) ;
list_for_each_entry ( devlink , & devlink_list , list ) {
if ( ! net_eq ( devlink_net ( devlink ) , sock_net ( msg - > sk ) ) )
continue ;
list_for_each_entry ( devlink_sb , & devlink - > sb_list , list ) {
if ( idx < start ) {
idx + + ;
continue ;
}
err = devlink_nl_sb_fill ( msg , devlink , devlink_sb ,
DEVLINK_CMD_SB_NEW ,
NETLINK_CB ( cb - > skb ) . portid ,
cb - > nlh - > nlmsg_seq ,
NLM_F_MULTI ) ;
if ( err )
goto out ;
idx + + ;
}
}
out :
mutex_unlock ( & devlink_mutex ) ;
cb - > args [ 0 ] = idx ;
return msg - > len ;
}
static int devlink_nl_sb_pool_fill ( struct sk_buff * msg , struct devlink * devlink ,
struct devlink_sb * devlink_sb ,
u16 pool_index , enum devlink_command cmd ,
u32 portid , u32 seq , int flags )
{
struct devlink_sb_pool_info pool_info ;
void * hdr ;
int err ;
err = devlink - > ops - > sb_pool_get ( devlink , devlink_sb - > index ,
pool_index , & pool_info ) ;
if ( err )
return err ;
hdr = genlmsg_put ( msg , portid , seq , & devlink_nl_family , flags , cmd ) ;
if ( ! hdr )
return - EMSGSIZE ;
if ( devlink_nl_put_handle ( msg , devlink ) )
goto nla_put_failure ;
if ( nla_put_u32 ( msg , DEVLINK_ATTR_SB_INDEX , devlink_sb - > index ) )
goto nla_put_failure ;
if ( nla_put_u16 ( msg , DEVLINK_ATTR_SB_POOL_INDEX , pool_index ) )
goto nla_put_failure ;
if ( nla_put_u8 ( msg , DEVLINK_ATTR_SB_POOL_TYPE , pool_info . pool_type ) )
goto nla_put_failure ;
if ( nla_put_u32 ( msg , DEVLINK_ATTR_SB_POOL_SIZE , pool_info . size ) )
goto nla_put_failure ;
if ( nla_put_u8 ( msg , DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE ,
pool_info . threshold_type ) )
goto nla_put_failure ;
genlmsg_end ( msg , hdr ) ;
return 0 ;
nla_put_failure :
genlmsg_cancel ( msg , hdr ) ;
return - EMSGSIZE ;
}
static int devlink_nl_cmd_sb_pool_get_doit ( struct sk_buff * skb ,
struct genl_info * info )
{
struct devlink * devlink = info - > user_ptr [ 0 ] ;
struct devlink_sb * devlink_sb = info - > user_ptr [ 1 ] ;
struct sk_buff * msg ;
u16 pool_index ;
int err ;
err = devlink_sb_pool_index_get_from_info ( devlink_sb , info ,
& pool_index ) ;
if ( err )
return err ;
if ( ! devlink - > ops | | ! devlink - > ops - > sb_pool_get )
return - EOPNOTSUPP ;
msg = nlmsg_new ( NLMSG_DEFAULT_SIZE , GFP_KERNEL ) ;
if ( ! msg )
return - ENOMEM ;
err = devlink_nl_sb_pool_fill ( msg , devlink , devlink_sb , pool_index ,
DEVLINK_CMD_SB_POOL_NEW ,
info - > snd_portid , info - > snd_seq , 0 ) ;
if ( err ) {
nlmsg_free ( msg ) ;
return err ;
}
return genlmsg_reply ( msg , info ) ;
}
static int __sb_pool_get_dumpit ( struct sk_buff * msg , int start , int * p_idx ,
struct devlink * devlink ,
struct devlink_sb * devlink_sb ,
u32 portid , u32 seq )
{
u16 pool_count = devlink_sb_pool_count ( devlink_sb ) ;
u16 pool_index ;
int err ;
for ( pool_index = 0 ; pool_index < pool_count ; pool_index + + ) {
if ( * p_idx < start ) {
( * p_idx ) + + ;
continue ;
}
err = devlink_nl_sb_pool_fill ( msg , devlink ,
devlink_sb ,
pool_index ,
DEVLINK_CMD_SB_POOL_NEW ,
portid , seq , NLM_F_MULTI ) ;
if ( err )
return err ;
( * p_idx ) + + ;
}
return 0 ;
}
static int devlink_nl_cmd_sb_pool_get_dumpit ( struct sk_buff * msg ,
struct netlink_callback * cb )
{
struct devlink * devlink ;
struct devlink_sb * devlink_sb ;
int start = cb - > args [ 0 ] ;
int idx = 0 ;
int err ;
mutex_lock ( & devlink_mutex ) ;
list_for_each_entry ( devlink , & devlink_list , list ) {
if ( ! net_eq ( devlink_net ( devlink ) , sock_net ( msg - > sk ) ) | |
! devlink - > ops | | ! devlink - > ops - > sb_pool_get )
continue ;
list_for_each_entry ( devlink_sb , & devlink - > sb_list , list ) {
err = __sb_pool_get_dumpit ( msg , start , & idx , devlink ,
devlink_sb ,
NETLINK_CB ( cb - > skb ) . portid ,
cb - > nlh - > nlmsg_seq ) ;
if ( err & & err ! = - EOPNOTSUPP )
goto out ;
}
}
out :
mutex_unlock ( & devlink_mutex ) ;
cb - > args [ 0 ] = idx ;
return msg - > len ;
}
static int devlink_sb_pool_set ( struct devlink * devlink , unsigned int sb_index ,
u16 pool_index , u32 size ,
enum devlink_sb_threshold_type threshold_type )
{
const struct devlink_ops * ops = devlink - > ops ;
if ( ops & & ops - > sb_pool_set )
return ops - > sb_pool_set ( devlink , sb_index , pool_index ,
size , threshold_type ) ;
return - EOPNOTSUPP ;
}
static int devlink_nl_cmd_sb_pool_set_doit ( struct sk_buff * skb ,
struct genl_info * info )
{
struct devlink * devlink = info - > user_ptr [ 0 ] ;
struct devlink_sb * devlink_sb = info - > user_ptr [ 1 ] ;
enum devlink_sb_threshold_type threshold_type ;
u16 pool_index ;
u32 size ;
int err ;
err = devlink_sb_pool_index_get_from_info ( devlink_sb , info ,
& pool_index ) ;
if ( err )
return err ;
err = devlink_sb_th_type_get_from_info ( info , & threshold_type ) ;
if ( err )
return err ;
if ( ! info - > attrs [ DEVLINK_ATTR_SB_POOL_SIZE ] )
return - EINVAL ;
size = nla_get_u32 ( info - > attrs [ DEVLINK_ATTR_SB_POOL_SIZE ] ) ;
return devlink_sb_pool_set ( devlink , devlink_sb - > index ,
pool_index , size , threshold_type ) ;
}
static int devlink_nl_sb_port_pool_fill ( struct sk_buff * msg ,
struct devlink * devlink ,
struct devlink_port * devlink_port ,
struct devlink_sb * devlink_sb ,
u16 pool_index ,
enum devlink_command cmd ,
u32 portid , u32 seq , int flags )
{
2016-04-14 19:19:14 +03:00
const struct devlink_ops * ops = devlink - > ops ;
2016-04-14 19:19:13 +03:00
u32 threshold ;
void * hdr ;
int err ;
2016-04-14 19:19:14 +03:00
err = ops - > sb_port_pool_get ( devlink_port , devlink_sb - > index ,
pool_index , & threshold ) ;
2016-04-14 19:19:13 +03:00
if ( err )
return err ;
hdr = genlmsg_put ( msg , portid , seq , & devlink_nl_family , flags , cmd ) ;
if ( ! hdr )
return - EMSGSIZE ;
if ( devlink_nl_put_handle ( msg , devlink ) )
goto nla_put_failure ;
if ( nla_put_u32 ( msg , DEVLINK_ATTR_PORT_INDEX , devlink_port - > index ) )
goto nla_put_failure ;
if ( nla_put_u32 ( msg , DEVLINK_ATTR_SB_INDEX , devlink_sb - > index ) )
goto nla_put_failure ;
if ( nla_put_u16 ( msg , DEVLINK_ATTR_SB_POOL_INDEX , pool_index ) )
goto nla_put_failure ;
if ( nla_put_u32 ( msg , DEVLINK_ATTR_SB_THRESHOLD , threshold ) )
goto nla_put_failure ;
2016-04-14 19:19:14 +03:00
if ( ops - > sb_occ_port_pool_get ) {
u32 cur ;
u32 max ;
err = ops - > sb_occ_port_pool_get ( devlink_port , devlink_sb - > index ,
pool_index , & cur , & max ) ;
if ( err & & err ! = - EOPNOTSUPP )
return err ;
if ( ! err ) {
if ( nla_put_u32 ( msg , DEVLINK_ATTR_SB_OCC_CUR , cur ) )
goto nla_put_failure ;
if ( nla_put_u32 ( msg , DEVLINK_ATTR_SB_OCC_MAX , max ) )
goto nla_put_failure ;
}
}
2016-04-14 19:19:13 +03:00
genlmsg_end ( msg , hdr ) ;
return 0 ;
nla_put_failure :
genlmsg_cancel ( msg , hdr ) ;
return - EMSGSIZE ;
}
static int devlink_nl_cmd_sb_port_pool_get_doit ( struct sk_buff * skb ,
struct genl_info * info )
{
struct devlink_port * devlink_port = info - > user_ptr [ 0 ] ;
struct devlink * devlink = devlink_port - > devlink ;
struct devlink_sb * devlink_sb = info - > user_ptr [ 1 ] ;
struct sk_buff * msg ;
u16 pool_index ;
int err ;
err = devlink_sb_pool_index_get_from_info ( devlink_sb , info ,
& pool_index ) ;
if ( err )
return err ;
if ( ! devlink - > ops | | ! devlink - > ops - > sb_port_pool_get )
return - EOPNOTSUPP ;
msg = nlmsg_new ( NLMSG_DEFAULT_SIZE , GFP_KERNEL ) ;
if ( ! msg )
return - ENOMEM ;
err = devlink_nl_sb_port_pool_fill ( msg , devlink , devlink_port ,
devlink_sb , pool_index ,
DEVLINK_CMD_SB_PORT_POOL_NEW ,
info - > snd_portid , info - > snd_seq , 0 ) ;
if ( err ) {
nlmsg_free ( msg ) ;
return err ;
}
return genlmsg_reply ( msg , info ) ;
}
static int __sb_port_pool_get_dumpit ( struct sk_buff * msg , int start , int * p_idx ,
struct devlink * devlink ,
struct devlink_sb * devlink_sb ,
u32 portid , u32 seq )
{
struct devlink_port * devlink_port ;
u16 pool_count = devlink_sb_pool_count ( devlink_sb ) ;
u16 pool_index ;
int err ;
list_for_each_entry ( devlink_port , & devlink - > port_list , list ) {
for ( pool_index = 0 ; pool_index < pool_count ; pool_index + + ) {
if ( * p_idx < start ) {
( * p_idx ) + + ;
continue ;
}
err = devlink_nl_sb_port_pool_fill ( msg , devlink ,
devlink_port ,
devlink_sb ,
pool_index ,
DEVLINK_CMD_SB_PORT_POOL_NEW ,
portid , seq ,
NLM_F_MULTI ) ;
if ( err )
return err ;
( * p_idx ) + + ;
}
}
return 0 ;
}
static int devlink_nl_cmd_sb_port_pool_get_dumpit ( struct sk_buff * msg ,
struct netlink_callback * cb )
{
struct devlink * devlink ;
struct devlink_sb * devlink_sb ;
int start = cb - > args [ 0 ] ;
int idx = 0 ;
int err ;
mutex_lock ( & devlink_mutex ) ;
mutex_lock ( & devlink_port_mutex ) ;
list_for_each_entry ( devlink , & devlink_list , list ) {
if ( ! net_eq ( devlink_net ( devlink ) , sock_net ( msg - > sk ) ) | |
! devlink - > ops | | ! devlink - > ops - > sb_port_pool_get )
continue ;
list_for_each_entry ( devlink_sb , & devlink - > sb_list , list ) {
err = __sb_port_pool_get_dumpit ( msg , start , & idx ,
devlink , devlink_sb ,
NETLINK_CB ( cb - > skb ) . portid ,
cb - > nlh - > nlmsg_seq ) ;
if ( err & & err ! = - EOPNOTSUPP )
goto out ;
}
}
out :
mutex_unlock ( & devlink_port_mutex ) ;
mutex_unlock ( & devlink_mutex ) ;
cb - > args [ 0 ] = idx ;
return msg - > len ;
}
static int devlink_sb_port_pool_set ( struct devlink_port * devlink_port ,
unsigned int sb_index , u16 pool_index ,
u32 threshold )
{
const struct devlink_ops * ops = devlink_port - > devlink - > ops ;
if ( ops & & ops - > sb_port_pool_set )
return ops - > sb_port_pool_set ( devlink_port , sb_index ,
pool_index , threshold ) ;
return - EOPNOTSUPP ;
}
static int devlink_nl_cmd_sb_port_pool_set_doit ( struct sk_buff * skb ,
struct genl_info * info )
{
struct devlink_port * devlink_port = info - > user_ptr [ 0 ] ;
struct devlink_sb * devlink_sb = info - > user_ptr [ 1 ] ;
u16 pool_index ;
u32 threshold ;
int err ;
err = devlink_sb_pool_index_get_from_info ( devlink_sb , info ,
& pool_index ) ;
if ( err )
return err ;
if ( ! info - > attrs [ DEVLINK_ATTR_SB_THRESHOLD ] )
return - EINVAL ;
threshold = nla_get_u32 ( info - > attrs [ DEVLINK_ATTR_SB_THRESHOLD ] ) ;
return devlink_sb_port_pool_set ( devlink_port , devlink_sb - > index ,
pool_index , threshold ) ;
}
static int
devlink_nl_sb_tc_pool_bind_fill ( struct sk_buff * msg , struct devlink * devlink ,
struct devlink_port * devlink_port ,
struct devlink_sb * devlink_sb , u16 tc_index ,
enum devlink_sb_pool_type pool_type ,
enum devlink_command cmd ,
u32 portid , u32 seq , int flags )
{
2016-04-14 19:19:14 +03:00
const struct devlink_ops * ops = devlink - > ops ;
2016-04-14 19:19:13 +03:00
u16 pool_index ;
u32 threshold ;
void * hdr ;
int err ;
2016-04-14 19:19:14 +03:00
err = ops - > sb_tc_pool_bind_get ( devlink_port , devlink_sb - > index ,
tc_index , pool_type ,
& pool_index , & threshold ) ;
2016-04-14 19:19:13 +03:00
if ( err )
return err ;
hdr = genlmsg_put ( msg , portid , seq , & devlink_nl_family , flags , cmd ) ;
if ( ! hdr )
return - EMSGSIZE ;
if ( devlink_nl_put_handle ( msg , devlink ) )
goto nla_put_failure ;
if ( nla_put_u32 ( msg , DEVLINK_ATTR_PORT_INDEX , devlink_port - > index ) )
goto nla_put_failure ;
if ( nla_put_u32 ( msg , DEVLINK_ATTR_SB_INDEX , devlink_sb - > index ) )
goto nla_put_failure ;
if ( nla_put_u16 ( msg , DEVLINK_ATTR_SB_TC_INDEX , tc_index ) )
goto nla_put_failure ;
if ( nla_put_u8 ( msg , DEVLINK_ATTR_SB_POOL_TYPE , pool_type ) )
goto nla_put_failure ;
if ( nla_put_u16 ( msg , DEVLINK_ATTR_SB_POOL_INDEX , pool_index ) )
goto nla_put_failure ;
if ( nla_put_u32 ( msg , DEVLINK_ATTR_SB_THRESHOLD , threshold ) )
goto nla_put_failure ;
2016-04-14 19:19:14 +03:00
if ( ops - > sb_occ_tc_port_bind_get ) {
u32 cur ;
u32 max ;
err = ops - > sb_occ_tc_port_bind_get ( devlink_port ,
devlink_sb - > index ,
tc_index , pool_type ,
& cur , & max ) ;
if ( err & & err ! = - EOPNOTSUPP )
return err ;
if ( ! err ) {
if ( nla_put_u32 ( msg , DEVLINK_ATTR_SB_OCC_CUR , cur ) )
goto nla_put_failure ;
if ( nla_put_u32 ( msg , DEVLINK_ATTR_SB_OCC_MAX , max ) )
goto nla_put_failure ;
}
}
2016-04-14 19:19:13 +03:00
genlmsg_end ( msg , hdr ) ;
return 0 ;
nla_put_failure :
genlmsg_cancel ( msg , hdr ) ;
return - EMSGSIZE ;
}
static int devlink_nl_cmd_sb_tc_pool_bind_get_doit ( struct sk_buff * skb ,
struct genl_info * info )
{
struct devlink_port * devlink_port = info - > user_ptr [ 0 ] ;
struct devlink * devlink = devlink_port - > devlink ;
struct devlink_sb * devlink_sb = info - > user_ptr [ 1 ] ;
struct sk_buff * msg ;
enum devlink_sb_pool_type pool_type ;
u16 tc_index ;
int err ;
err = devlink_sb_pool_type_get_from_info ( info , & pool_type ) ;
if ( err )
return err ;
err = devlink_sb_tc_index_get_from_info ( devlink_sb , info ,
pool_type , & tc_index ) ;
if ( err )
return err ;
if ( ! devlink - > ops | | ! devlink - > ops - > sb_tc_pool_bind_get )
return - EOPNOTSUPP ;
msg = nlmsg_new ( NLMSG_DEFAULT_SIZE , GFP_KERNEL ) ;
if ( ! msg )
return - ENOMEM ;
err = devlink_nl_sb_tc_pool_bind_fill ( msg , devlink , devlink_port ,
devlink_sb , tc_index , pool_type ,
DEVLINK_CMD_SB_TC_POOL_BIND_NEW ,
info - > snd_portid ,
info - > snd_seq , 0 ) ;
if ( err ) {
nlmsg_free ( msg ) ;
return err ;
}
return genlmsg_reply ( msg , info ) ;
}
static int __sb_tc_pool_bind_get_dumpit ( struct sk_buff * msg ,
int start , int * p_idx ,
struct devlink * devlink ,
struct devlink_sb * devlink_sb ,
u32 portid , u32 seq )
{
struct devlink_port * devlink_port ;
u16 tc_index ;
int err ;
list_for_each_entry ( devlink_port , & devlink - > port_list , list ) {
for ( tc_index = 0 ;
tc_index < devlink_sb - > ingress_tc_count ; tc_index + + ) {
if ( * p_idx < start ) {
( * p_idx ) + + ;
continue ;
}
err = devlink_nl_sb_tc_pool_bind_fill ( msg , devlink ,
devlink_port ,
devlink_sb ,
tc_index ,
DEVLINK_SB_POOL_TYPE_INGRESS ,
DEVLINK_CMD_SB_TC_POOL_BIND_NEW ,
portid , seq ,
NLM_F_MULTI ) ;
if ( err )
return err ;
( * p_idx ) + + ;
}
for ( tc_index = 0 ;
tc_index < devlink_sb - > egress_tc_count ; tc_index + + ) {
if ( * p_idx < start ) {
( * p_idx ) + + ;
continue ;
}
err = devlink_nl_sb_tc_pool_bind_fill ( msg , devlink ,
devlink_port ,
devlink_sb ,
tc_index ,
DEVLINK_SB_POOL_TYPE_EGRESS ,
DEVLINK_CMD_SB_TC_POOL_BIND_NEW ,
portid , seq ,
NLM_F_MULTI ) ;
if ( err )
return err ;
( * p_idx ) + + ;
}
}
return 0 ;
}
static int
devlink_nl_cmd_sb_tc_pool_bind_get_dumpit ( struct sk_buff * msg ,
struct netlink_callback * cb )
{
struct devlink * devlink ;
struct devlink_sb * devlink_sb ;
int start = cb - > args [ 0 ] ;
int idx = 0 ;
int err ;
mutex_lock ( & devlink_mutex ) ;
mutex_lock ( & devlink_port_mutex ) ;
list_for_each_entry ( devlink , & devlink_list , list ) {
if ( ! net_eq ( devlink_net ( devlink ) , sock_net ( msg - > sk ) ) | |
! devlink - > ops | | ! devlink - > ops - > sb_tc_pool_bind_get )
continue ;
list_for_each_entry ( devlink_sb , & devlink - > sb_list , list ) {
err = __sb_tc_pool_bind_get_dumpit ( msg , start , & idx ,
devlink ,
devlink_sb ,
NETLINK_CB ( cb - > skb ) . portid ,
cb - > nlh - > nlmsg_seq ) ;
if ( err & & err ! = - EOPNOTSUPP )
goto out ;
}
}
out :
mutex_unlock ( & devlink_port_mutex ) ;
mutex_unlock ( & devlink_mutex ) ;
cb - > args [ 0 ] = idx ;
return msg - > len ;
}
static int devlink_sb_tc_pool_bind_set ( struct devlink_port * devlink_port ,
unsigned int sb_index , u16 tc_index ,
enum devlink_sb_pool_type pool_type ,
u16 pool_index , u32 threshold )
{
const struct devlink_ops * ops = devlink_port - > devlink - > ops ;
if ( ops & & ops - > sb_tc_pool_bind_set )
return ops - > sb_tc_pool_bind_set ( devlink_port , sb_index ,
tc_index , pool_type ,
pool_index , threshold ) ;
return - EOPNOTSUPP ;
}
static int devlink_nl_cmd_sb_tc_pool_bind_set_doit ( struct sk_buff * skb ,
struct genl_info * info )
{
struct devlink_port * devlink_port = info - > user_ptr [ 0 ] ;
struct devlink_sb * devlink_sb = info - > user_ptr [ 1 ] ;
enum devlink_sb_pool_type pool_type ;
u16 tc_index ;
u16 pool_index ;
u32 threshold ;
int err ;
err = devlink_sb_pool_type_get_from_info ( info , & pool_type ) ;
if ( err )
return err ;
err = devlink_sb_tc_index_get_from_info ( devlink_sb , info ,
pool_type , & tc_index ) ;
if ( err )
return err ;
err = devlink_sb_pool_index_get_from_info ( devlink_sb , info ,
& pool_index ) ;
if ( err )
return err ;
if ( ! info - > attrs [ DEVLINK_ATTR_SB_THRESHOLD ] )
return - EINVAL ;
threshold = nla_get_u32 ( info - > attrs [ DEVLINK_ATTR_SB_THRESHOLD ] ) ;
return devlink_sb_tc_pool_bind_set ( devlink_port , devlink_sb - > index ,
tc_index , pool_type ,
pool_index , threshold ) ;
}
2016-04-14 19:19:14 +03:00
static int devlink_nl_cmd_sb_occ_snapshot_doit ( struct sk_buff * skb ,
struct genl_info * info )
{
struct devlink * devlink = info - > user_ptr [ 0 ] ;
struct devlink_sb * devlink_sb = info - > user_ptr [ 1 ] ;
const struct devlink_ops * ops = devlink - > ops ;
if ( ops & & ops - > sb_occ_snapshot )
return ops - > sb_occ_snapshot ( devlink , devlink_sb - > index ) ;
return - EOPNOTSUPP ;
}
static int devlink_nl_cmd_sb_occ_max_clear_doit ( struct sk_buff * skb ,
struct genl_info * info )
{
struct devlink * devlink = info - > user_ptr [ 0 ] ;
struct devlink_sb * devlink_sb = info - > user_ptr [ 1 ] ;
const struct devlink_ops * ops = devlink - > ops ;
if ( ops & & ops - > sb_occ_max_clear )
return ops - > sb_occ_max_clear ( devlink , devlink_sb - > index ) ;
return - EOPNOTSUPP ;
}
2017-02-09 17:54:34 +03:00
static int devlink_nl_eswitch_fill ( struct sk_buff * msg , struct devlink * devlink ,
enum devlink_command cmd , u32 portid ,
u32 seq , int flags )
2016-07-01 14:51:01 +03:00
{
2016-11-23 00:09:57 +03:00
const struct devlink_ops * ops = devlink - > ops ;
2016-09-25 13:52:44 +03:00
u8 inline_mode , encap_mode ;
2016-07-01 14:51:01 +03:00
void * hdr ;
2016-11-23 00:09:57 +03:00
int err = 0 ;
u16 mode ;
2016-07-01 14:51:01 +03:00
hdr = genlmsg_put ( msg , portid , seq , & devlink_nl_family , flags , cmd ) ;
if ( ! hdr )
return - EMSGSIZE ;
2016-11-23 00:09:57 +03:00
err = devlink_nl_put_handle ( msg , devlink ) ;
if ( err )
2017-02-09 17:54:35 +03:00
goto nla_put_failure ;
2016-07-01 14:51:01 +03:00
2017-02-09 17:54:36 +03:00
if ( ops - > eswitch_mode_get ) {
err = ops - > eswitch_mode_get ( devlink , & mode ) ;
if ( err )
goto nla_put_failure ;
err = nla_put_u16 ( msg , DEVLINK_ATTR_ESWITCH_MODE , mode ) ;
if ( err )
goto nla_put_failure ;
}
2016-11-23 00:09:57 +03:00
if ( ops - > eswitch_inline_mode_get ) {
err = ops - > eswitch_inline_mode_get ( devlink , & inline_mode ) ;
if ( err )
2017-02-09 17:54:35 +03:00
goto nla_put_failure ;
2016-11-23 00:09:57 +03:00
err = nla_put_u8 ( msg , DEVLINK_ATTR_ESWITCH_INLINE_MODE ,
inline_mode ) ;
if ( err )
2017-02-09 17:54:35 +03:00
goto nla_put_failure ;
2016-11-23 00:09:57 +03:00
}
2016-07-01 14:51:01 +03:00
2016-09-25 13:52:44 +03:00
if ( ops - > eswitch_encap_mode_get ) {
err = ops - > eswitch_encap_mode_get ( devlink , & encap_mode ) ;
if ( err )
goto nla_put_failure ;
err = nla_put_u8 ( msg , DEVLINK_ATTR_ESWITCH_ENCAP_MODE , encap_mode ) ;
if ( err )
goto nla_put_failure ;
}
2016-07-01 14:51:01 +03:00
genlmsg_end ( msg , hdr ) ;
return 0 ;
2017-02-09 17:54:35 +03:00
nla_put_failure :
2016-07-01 14:51:01 +03:00
genlmsg_cancel ( msg , hdr ) ;
2016-11-23 00:09:57 +03:00
return err ;
2016-07-01 14:51:01 +03:00
}
2017-02-09 17:54:33 +03:00
static int devlink_nl_cmd_eswitch_get_doit ( struct sk_buff * skb ,
struct genl_info * info )
2016-07-01 14:51:01 +03:00
{
struct devlink * devlink = info - > user_ptr [ 0 ] ;
const struct devlink_ops * ops = devlink - > ops ;
struct sk_buff * msg ;
int err ;
2017-02-09 17:54:36 +03:00
if ( ! ops )
2016-07-01 14:51:01 +03:00
return - EOPNOTSUPP ;
msg = nlmsg_new ( NLMSG_DEFAULT_SIZE , GFP_KERNEL ) ;
if ( ! msg )
return - ENOMEM ;
2017-02-09 17:54:34 +03:00
err = devlink_nl_eswitch_fill ( msg , devlink , DEVLINK_CMD_ESWITCH_GET ,
info - > snd_portid , info - > snd_seq , 0 ) ;
2016-07-01 14:51:01 +03:00
if ( err ) {
nlmsg_free ( msg ) ;
return err ;
}
return genlmsg_reply ( msg , info ) ;
}
2017-02-09 17:54:33 +03:00
static int devlink_nl_cmd_eswitch_set_doit ( struct sk_buff * skb ,
struct genl_info * info )
2016-07-01 14:51:01 +03:00
{
struct devlink * devlink = info - > user_ptr [ 0 ] ;
const struct devlink_ops * ops = devlink - > ops ;
2016-09-25 13:52:44 +03:00
u8 inline_mode , encap_mode ;
2016-11-23 00:09:57 +03:00
int err = 0 ;
2016-09-25 13:52:44 +03:00
u16 mode ;
2016-07-01 14:51:01 +03:00
2016-11-23 00:09:57 +03:00
if ( ! ops )
return - EOPNOTSUPP ;
2016-07-01 14:51:01 +03:00
2016-11-23 00:09:57 +03:00
if ( info - > attrs [ DEVLINK_ATTR_ESWITCH_MODE ] ) {
if ( ! ops - > eswitch_mode_set )
return - EOPNOTSUPP ;
mode = nla_get_u16 ( info - > attrs [ DEVLINK_ATTR_ESWITCH_MODE ] ) ;
err = ops - > eswitch_mode_set ( devlink , mode ) ;
if ( err )
return err ;
}
2016-07-01 14:51:01 +03:00
2016-11-23 00:09:57 +03:00
if ( info - > attrs [ DEVLINK_ATTR_ESWITCH_INLINE_MODE ] ) {
if ( ! ops - > eswitch_inline_mode_set )
return - EOPNOTSUPP ;
inline_mode = nla_get_u8 (
info - > attrs [ DEVLINK_ATTR_ESWITCH_INLINE_MODE ] ) ;
err = ops - > eswitch_inline_mode_set ( devlink , inline_mode ) ;
if ( err )
return err ;
}
2016-09-25 13:52:44 +03:00
if ( info - > attrs [ DEVLINK_ATTR_ESWITCH_ENCAP_MODE ] ) {
if ( ! ops - > eswitch_encap_mode_set )
return - EOPNOTSUPP ;
encap_mode = nla_get_u8 ( info - > attrs [ DEVLINK_ATTR_ESWITCH_ENCAP_MODE ] ) ;
err = ops - > eswitch_encap_mode_set ( devlink , encap_mode ) ;
if ( err )
return err ;
}
2017-03-28 18:24:10 +03:00
return 0 ;
}
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 ( 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 ( 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 ( 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 ( 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 ;
2017-08-24 09:40:02 +03:00
u64 table_size ;
2017-03-28 18:24:10 +03:00
2017-08-24 09:40:02 +03:00
table_size = table - > table_ops - > size_get ( table - > priv ) ;
2017-03-28 18:24:10 +03:00
table_attr = nla_nest_start ( skb , DEVLINK_ATTR_DPIPE_TABLE ) ;
if ( ! table_attr )
return - EMSGSIZE ;
if ( nla_put_string ( skb , DEVLINK_ATTR_DPIPE_TABLE_NAME , table - > name ) | |
2017-08-24 09:40:02 +03:00
nla_put_u64_64bit ( skb , DEVLINK_ATTR_DPIPE_TABLE_SIZE , table_size ,
2017-03-28 18:24:10 +03:00
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 ( 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 ) ;
2017-06-05 03:57:21 +03:00
if ( ! hdr ) {
nlmsg_free ( skb ) ;
2017-03-28 18:24:10 +03:00
return - EMSGSIZE ;
2017-06-05 03:57:21 +03:00
}
2017-03-28 18:24:10 +03:00
if ( devlink_nl_put_handle ( skb , devlink ) )
goto nla_put_failure ;
tables_attr = nla_nest_start ( 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 )
goto err_skb_send_alloc ;
goto send_done ;
}
return genlmsg_reply ( skb , info ) ;
nla_put_failure :
err = - EMSGSIZE ;
err_table_put :
err_skb_send_alloc :
genlmsg_cancel ( skb , hdr ) ;
nlmsg_free ( skb ) ;
return err ;
}
static int devlink_nl_cmd_dpipe_table_get ( struct sk_buff * skb ,
struct genl_info * info )
{
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 ( 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 ( 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 ( 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 ( 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 ( 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 ) ;
2016-11-23 00:09:57 +03:00
2017-03-28 18:24:10 +03:00
nla_nest_end ( skb , entry_attr ) ;
2016-11-23 00:09:57 +03:00
return 0 ;
2017-03-28 18:24:10 +03:00
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_dpipe_table * table ;
list_for_each_entry_rcu ( table , dpipe_tables , list ) {
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 ( dump_ctx - > skb ,
DEVLINK_ATTR_DPIPE_ENTRIES ) ;
if ( ! dump_ctx - > nest )
goto nla_put_failure ;
return 0 ;
nla_put_failure :
genlmsg_cancel ( dump_ctx - > skb , dump_ctx - > hdr ) ;
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 ) ;
2017-08-24 09:40:03 +03:00
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 ( devlink_dpipe_entry_clear ) ;
2017-03-28 18:24:10 +03:00
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 )
goto err_entries_dump ;
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 )
goto err_skb_send_alloc ;
goto send_done ;
}
return genlmsg_reply ( dump_ctx . skb , info ) ;
err_entries_dump :
err_skb_send_alloc :
genlmsg_cancel ( dump_ctx . skb , dump_ctx . hdr ) ;
nlmsg_free ( dump_ctx . skb ) ;
return err ;
}
static int devlink_nl_cmd_dpipe_entries_get ( struct sk_buff * skb ,
struct genl_info * info )
{
struct devlink * devlink = info - > user_ptr [ 0 ] ;
struct devlink_dpipe_table * table ;
const char * table_name ;
if ( ! info - > attrs [ 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 ) ;
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 ( 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 ( skb , DEVLINK_ATTR_DPIPE_HEADER ) ;
2017-04-11 19:02:02 +03:00
if ( ! header_attr )
2017-03-28 18:24:10 +03:00
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 ( 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 ) ;
2017-06-05 03:57:21 +03:00
if ( ! hdr ) {
nlmsg_free ( skb ) ;
2017-03-28 18:24:10 +03:00
return - EMSGSIZE ;
2017-06-05 03:57:21 +03:00
}
2017-03-28 18:24:10 +03:00
if ( devlink_nl_put_handle ( skb , devlink ) )
goto nla_put_failure ;
headers_attr = nla_nest_start ( 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 )
goto err_skb_send_alloc ;
goto send_done ;
}
return genlmsg_reply ( skb , info ) ;
nla_put_failure :
err = - EMSGSIZE ;
err_table_put :
err_skb_send_alloc :
genlmsg_cancel ( skb , hdr ) ;
nlmsg_free ( skb ) ;
return err ;
}
static int devlink_nl_cmd_dpipe_headers_get ( struct sk_buff * skb ,
struct genl_info * info )
{
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 ) ;
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 ;
}
static int devlink_nl_cmd_dpipe_table_counters_set ( struct sk_buff * skb ,
struct genl_info * info )
{
struct devlink * devlink = info - > user_ptr [ 0 ] ;
const char * table_name ;
bool counters_enable ;
if ( ! info - > attrs [ DEVLINK_ATTR_DPIPE_TABLE_NAME ] | |
! info - > attrs [ 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 ) ;
2016-07-01 14:51:01 +03:00
}
2016-02-26 19:32:23 +03:00
static const struct nla_policy devlink_nl_policy [ DEVLINK_ATTR_MAX + 1 ] = {
[ DEVLINK_ATTR_BUS_NAME ] = { . type = NLA_NUL_STRING } ,
[ DEVLINK_ATTR_DEV_NAME ] = { . type = NLA_NUL_STRING } ,
[ DEVLINK_ATTR_PORT_INDEX ] = { . type = NLA_U32 } ,
[ DEVLINK_ATTR_PORT_TYPE ] = { . type = NLA_U16 } ,
[ DEVLINK_ATTR_PORT_SPLIT_COUNT ] = { . type = NLA_U32 } ,
2016-04-14 19:19:13 +03:00
[ DEVLINK_ATTR_SB_INDEX ] = { . type = NLA_U32 } ,
[ DEVLINK_ATTR_SB_POOL_INDEX ] = { . type = NLA_U16 } ,
[ DEVLINK_ATTR_SB_POOL_TYPE ] = { . type = NLA_U8 } ,
[ DEVLINK_ATTR_SB_POOL_SIZE ] = { . type = NLA_U32 } ,
[ DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE ] = { . type = NLA_U8 } ,
[ DEVLINK_ATTR_SB_THRESHOLD ] = { . type = NLA_U32 } ,
[ DEVLINK_ATTR_SB_TC_INDEX ] = { . type = NLA_U16 } ,
2016-07-01 14:51:01 +03:00
[ DEVLINK_ATTR_ESWITCH_MODE ] = { . type = NLA_U16 } ,
2016-11-23 00:09:57 +03:00
[ DEVLINK_ATTR_ESWITCH_INLINE_MODE ] = { . type = NLA_U8 } ,
2016-09-25 13:52:44 +03:00
[ DEVLINK_ATTR_ESWITCH_ENCAP_MODE ] = { . type = NLA_U8 } ,
2017-03-28 18:24:10 +03:00
[ DEVLINK_ATTR_DPIPE_TABLE_NAME ] = { . type = NLA_NUL_STRING } ,
[ DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED ] = { . type = NLA_U8 } ,
2016-02-26 19:32:23 +03:00
} ;
static const struct genl_ops devlink_nl_ops [ ] = {
{
. cmd = DEVLINK_CMD_GET ,
. doit = devlink_nl_cmd_get_doit ,
. dumpit = devlink_nl_cmd_get_dumpit ,
. policy = devlink_nl_policy ,
2016-04-08 20:12:48 +03:00
. internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK ,
2016-02-26 19:32:23 +03:00
/* can be retrieved by unprivileged users */
} ,
{
. cmd = DEVLINK_CMD_PORT_GET ,
. doit = devlink_nl_cmd_port_get_doit ,
. dumpit = devlink_nl_cmd_port_get_dumpit ,
. policy = devlink_nl_policy ,
. internal_flags = DEVLINK_NL_FLAG_NEED_PORT ,
/* can be retrieved by unprivileged users */
} ,
{
. cmd = DEVLINK_CMD_PORT_SET ,
. doit = devlink_nl_cmd_port_set_doit ,
. policy = devlink_nl_policy ,
. flags = GENL_ADMIN_PERM ,
. internal_flags = DEVLINK_NL_FLAG_NEED_PORT ,
} ,
{
. cmd = DEVLINK_CMD_PORT_SPLIT ,
. doit = devlink_nl_cmd_port_split_doit ,
. policy = devlink_nl_policy ,
. flags = GENL_ADMIN_PERM ,
2016-04-08 20:12:48 +03:00
. internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK ,
2016-02-26 19:32:23 +03:00
} ,
{
. cmd = DEVLINK_CMD_PORT_UNSPLIT ,
. doit = devlink_nl_cmd_port_unsplit_doit ,
. policy = devlink_nl_policy ,
. flags = GENL_ADMIN_PERM ,
2016-04-08 20:12:48 +03:00
. internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK ,
2016-02-26 19:32:23 +03:00
} ,
2016-04-14 19:19:13 +03:00
{
. cmd = DEVLINK_CMD_SB_GET ,
. doit = devlink_nl_cmd_sb_get_doit ,
. dumpit = devlink_nl_cmd_sb_get_dumpit ,
. policy = devlink_nl_policy ,
. internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
DEVLINK_NL_FLAG_NEED_SB ,
/* can be retrieved by unprivileged users */
} ,
{
. cmd = DEVLINK_CMD_SB_POOL_GET ,
. doit = devlink_nl_cmd_sb_pool_get_doit ,
. dumpit = devlink_nl_cmd_sb_pool_get_dumpit ,
. policy = devlink_nl_policy ,
. internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
DEVLINK_NL_FLAG_NEED_SB ,
/* can be retrieved by unprivileged users */
} ,
{
. cmd = DEVLINK_CMD_SB_POOL_SET ,
. doit = devlink_nl_cmd_sb_pool_set_doit ,
. policy = devlink_nl_policy ,
. flags = GENL_ADMIN_PERM ,
. internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
DEVLINK_NL_FLAG_NEED_SB ,
} ,
{
. cmd = DEVLINK_CMD_SB_PORT_POOL_GET ,
. doit = devlink_nl_cmd_sb_port_pool_get_doit ,
. dumpit = devlink_nl_cmd_sb_port_pool_get_dumpit ,
. policy = devlink_nl_policy ,
. internal_flags = DEVLINK_NL_FLAG_NEED_PORT |
DEVLINK_NL_FLAG_NEED_SB ,
/* can be retrieved by unprivileged users */
} ,
{
. cmd = DEVLINK_CMD_SB_PORT_POOL_SET ,
. doit = devlink_nl_cmd_sb_port_pool_set_doit ,
. policy = devlink_nl_policy ,
. flags = GENL_ADMIN_PERM ,
. internal_flags = DEVLINK_NL_FLAG_NEED_PORT |
DEVLINK_NL_FLAG_NEED_SB ,
} ,
{
. cmd = DEVLINK_CMD_SB_TC_POOL_BIND_GET ,
. doit = devlink_nl_cmd_sb_tc_pool_bind_get_doit ,
. dumpit = devlink_nl_cmd_sb_tc_pool_bind_get_dumpit ,
. policy = devlink_nl_policy ,
. internal_flags = DEVLINK_NL_FLAG_NEED_PORT |
DEVLINK_NL_FLAG_NEED_SB ,
/* can be retrieved by unprivileged users */
} ,
{
. cmd = DEVLINK_CMD_SB_TC_POOL_BIND_SET ,
. doit = devlink_nl_cmd_sb_tc_pool_bind_set_doit ,
. policy = devlink_nl_policy ,
. flags = GENL_ADMIN_PERM ,
. internal_flags = DEVLINK_NL_FLAG_NEED_PORT |
DEVLINK_NL_FLAG_NEED_SB ,
} ,
2016-04-14 19:19:14 +03:00
{
. cmd = DEVLINK_CMD_SB_OCC_SNAPSHOT ,
. doit = devlink_nl_cmd_sb_occ_snapshot_doit ,
. policy = devlink_nl_policy ,
. flags = GENL_ADMIN_PERM ,
. internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
DEVLINK_NL_FLAG_NEED_SB |
DEVLINK_NL_FLAG_LOCK_PORTS ,
} ,
{
. cmd = DEVLINK_CMD_SB_OCC_MAX_CLEAR ,
. doit = devlink_nl_cmd_sb_occ_max_clear_doit ,
. policy = devlink_nl_policy ,
. flags = GENL_ADMIN_PERM ,
. internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
DEVLINK_NL_FLAG_NEED_SB |
DEVLINK_NL_FLAG_LOCK_PORTS ,
} ,
2016-07-01 14:51:01 +03:00
{
2017-02-09 17:54:33 +03:00
. cmd = DEVLINK_CMD_ESWITCH_GET ,
. doit = devlink_nl_cmd_eswitch_get_doit ,
2016-07-01 14:51:01 +03:00
. policy = devlink_nl_policy ,
. flags = GENL_ADMIN_PERM ,
. internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK ,
} ,
{
2017-02-09 17:54:33 +03:00
. cmd = DEVLINK_CMD_ESWITCH_SET ,
. doit = devlink_nl_cmd_eswitch_set_doit ,
2016-07-01 14:51:01 +03:00
. policy = devlink_nl_policy ,
. flags = GENL_ADMIN_PERM ,
. internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK ,
} ,
2017-03-28 18:24:10 +03:00
{
. cmd = DEVLINK_CMD_DPIPE_TABLE_GET ,
. doit = devlink_nl_cmd_dpipe_table_get ,
. policy = devlink_nl_policy ,
. flags = GENL_ADMIN_PERM ,
. internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK ,
} ,
{
. cmd = DEVLINK_CMD_DPIPE_ENTRIES_GET ,
. doit = devlink_nl_cmd_dpipe_entries_get ,
. policy = devlink_nl_policy ,
. flags = GENL_ADMIN_PERM ,
. internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK ,
} ,
{
. cmd = DEVLINK_CMD_DPIPE_HEADERS_GET ,
. doit = devlink_nl_cmd_dpipe_headers_get ,
. policy = devlink_nl_policy ,
. flags = GENL_ADMIN_PERM ,
. internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK ,
} ,
{
. cmd = DEVLINK_CMD_DPIPE_TABLE_COUNTERS_SET ,
. doit = devlink_nl_cmd_dpipe_table_counters_set ,
. policy = devlink_nl_policy ,
. flags = GENL_ADMIN_PERM ,
. internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK ,
} ,
2016-02-26 19:32:23 +03:00
} ;
2016-10-24 15:40:05 +03:00
static struct genl_family devlink_nl_family __ro_after_init = {
2016-10-24 15:40:03 +03:00
. name = DEVLINK_GENL_NAME ,
. version = DEVLINK_GENL_VERSION ,
. maxattr = DEVLINK_ATTR_MAX ,
. netnsok = true ,
. pre_doit = devlink_nl_pre_doit ,
. post_doit = devlink_nl_post_doit ,
. module = THIS_MODULE ,
. ops = devlink_nl_ops ,
. n_ops = ARRAY_SIZE ( devlink_nl_ops ) ,
. mcgrps = devlink_nl_mcgrps ,
. n_mcgrps = ARRAY_SIZE ( devlink_nl_mcgrps ) ,
} ;
2016-02-26 19:32:23 +03:00
/**
* devlink_alloc - Allocate new devlink instance resources
*
* @ ops : ops
* @ priv_size : size of user private data
*
* Allocate new devlink instance resources , including devlink index
* and name .
*/
struct devlink * devlink_alloc ( const struct devlink_ops * ops , size_t priv_size )
{
struct devlink * devlink ;
devlink = kzalloc ( sizeof ( * devlink ) + priv_size , GFP_KERNEL ) ;
if ( ! devlink )
return NULL ;
devlink - > ops = ops ;
devlink_net_set ( devlink , & init_net ) ;
INIT_LIST_HEAD ( & devlink - > port_list ) ;
2016-04-14 19:19:13 +03:00
INIT_LIST_HEAD ( & devlink - > sb_list ) ;
2017-03-28 18:24:10 +03:00
INIT_LIST_HEAD_RCU ( & devlink - > dpipe_table_list ) ;
2016-02-26 19:32:23 +03:00
return devlink ;
}
EXPORT_SYMBOL_GPL ( devlink_alloc ) ;
/**
* devlink_register - Register devlink instance
*
* @ devlink : devlink
*/
int devlink_register ( struct devlink * devlink , struct device * dev )
{
mutex_lock ( & devlink_mutex ) ;
devlink - > dev = dev ;
list_add_tail ( & devlink - > list , & devlink_list ) ;
devlink_notify ( devlink , DEVLINK_CMD_NEW ) ;
mutex_unlock ( & devlink_mutex ) ;
return 0 ;
}
EXPORT_SYMBOL_GPL ( devlink_register ) ;
/**
* devlink_unregister - Unregister devlink instance
*
* @ devlink : devlink
*/
void devlink_unregister ( struct devlink * devlink )
{
mutex_lock ( & devlink_mutex ) ;
devlink_notify ( devlink , DEVLINK_CMD_DEL ) ;
list_del ( & devlink - > list ) ;
mutex_unlock ( & devlink_mutex ) ;
}
EXPORT_SYMBOL_GPL ( devlink_unregister ) ;
/**
* devlink_free - Free devlink instance resources
*
* @ devlink : devlink
*/
void devlink_free ( struct devlink * devlink )
{
kfree ( devlink ) ;
}
EXPORT_SYMBOL_GPL ( devlink_free ) ;
/**
* devlink_port_register - Register devlink port
*
* @ devlink : devlink
* @ devlink_port : devlink port
* @ port_index
*
* Register devlink port with provided port index . User can use
* any indexing , even hw - related one . devlink_port structure
* is convenient to be embedded inside user driver private structure .
* Note that the caller should take care of zeroing the devlink_port
* structure .
*/
int devlink_port_register ( struct devlink * devlink ,
struct devlink_port * devlink_port ,
unsigned int port_index )
{
mutex_lock ( & devlink_port_mutex ) ;
if ( devlink_port_index_exists ( devlink , port_index ) ) {
mutex_unlock ( & devlink_port_mutex ) ;
return - EEXIST ;
}
devlink_port - > devlink = devlink ;
devlink_port - > index = port_index ;
devlink_port - > registered = true ;
list_add_tail ( & devlink_port - > list , & devlink - > port_list ) ;
mutex_unlock ( & devlink_port_mutex ) ;
devlink_port_notify ( devlink_port , DEVLINK_CMD_PORT_NEW ) ;
return 0 ;
}
EXPORT_SYMBOL_GPL ( devlink_port_register ) ;
/**
* devlink_port_unregister - Unregister devlink port
*
* @ devlink_port : devlink port
*/
void devlink_port_unregister ( struct devlink_port * devlink_port )
{
devlink_port_notify ( devlink_port , DEVLINK_CMD_PORT_DEL ) ;
mutex_lock ( & devlink_port_mutex ) ;
list_del ( & devlink_port - > list ) ;
mutex_unlock ( & devlink_port_mutex ) ;
}
EXPORT_SYMBOL_GPL ( devlink_port_unregister ) ;
static void __devlink_port_type_set ( struct devlink_port * devlink_port ,
enum devlink_port_type type ,
void * type_dev )
{
devlink_port - > type = type ;
devlink_port - > type_dev = type_dev ;
devlink_port_notify ( devlink_port , DEVLINK_CMD_PORT_NEW ) ;
}
/**
* devlink_port_type_eth_set - Set port type to Ethernet
*
* @ devlink_port : devlink port
* @ netdev : related netdevice
*/
void devlink_port_type_eth_set ( struct devlink_port * devlink_port ,
struct net_device * netdev )
{
return __devlink_port_type_set ( devlink_port ,
DEVLINK_PORT_TYPE_ETH , netdev ) ;
}
EXPORT_SYMBOL_GPL ( devlink_port_type_eth_set ) ;
/**
* devlink_port_type_ib_set - Set port type to InfiniBand
*
* @ devlink_port : devlink port
* @ ibdev : related IB device
*/
void devlink_port_type_ib_set ( struct devlink_port * devlink_port ,
struct ib_device * ibdev )
{
return __devlink_port_type_set ( devlink_port ,
DEVLINK_PORT_TYPE_IB , ibdev ) ;
}
EXPORT_SYMBOL_GPL ( devlink_port_type_ib_set ) ;
/**
* devlink_port_type_clear - Clear port type
*
* @ devlink_port : devlink port
*/
void devlink_port_type_clear ( struct devlink_port * devlink_port )
{
return __devlink_port_type_set ( devlink_port ,
DEVLINK_PORT_TYPE_NOTSET , NULL ) ;
}
EXPORT_SYMBOL_GPL ( devlink_port_type_clear ) ;
/**
* devlink_port_split_set - Set port is split
*
* @ devlink_port : devlink port
* @ split_group : split group - identifies group split port is part of
*/
void devlink_port_split_set ( struct devlink_port * devlink_port ,
u32 split_group )
{
devlink_port - > split = true ;
devlink_port - > split_group = split_group ;
devlink_port_notify ( devlink_port , DEVLINK_CMD_PORT_NEW ) ;
}
EXPORT_SYMBOL_GPL ( devlink_port_split_set ) ;
2016-04-14 19:19:13 +03:00
int devlink_sb_register ( struct devlink * devlink , unsigned int sb_index ,
u32 size , u16 ingress_pools_count ,
u16 egress_pools_count , u16 ingress_tc_count ,
u16 egress_tc_count )
{
struct devlink_sb * devlink_sb ;
int err = 0 ;
mutex_lock ( & devlink_mutex ) ;
if ( devlink_sb_index_exists ( devlink , sb_index ) ) {
err = - EEXIST ;
goto unlock ;
}
devlink_sb = kzalloc ( sizeof ( * devlink_sb ) , GFP_KERNEL ) ;
if ( ! devlink_sb ) {
err = - ENOMEM ;
goto unlock ;
}
devlink_sb - > index = sb_index ;
devlink_sb - > size = size ;
devlink_sb - > ingress_pools_count = ingress_pools_count ;
devlink_sb - > egress_pools_count = egress_pools_count ;
devlink_sb - > ingress_tc_count = ingress_tc_count ;
devlink_sb - > egress_tc_count = egress_tc_count ;
list_add_tail ( & devlink_sb - > list , & devlink - > sb_list ) ;
unlock :
mutex_unlock ( & devlink_mutex ) ;
return err ;
}
EXPORT_SYMBOL_GPL ( devlink_sb_register ) ;
void devlink_sb_unregister ( struct devlink * devlink , unsigned int sb_index )
{
struct devlink_sb * devlink_sb ;
mutex_lock ( & devlink_mutex ) ;
devlink_sb = devlink_sb_get_by_index ( devlink , sb_index ) ;
WARN_ON ( ! devlink_sb ) ;
list_del ( & devlink_sb - > list ) ;
mutex_unlock ( & devlink_mutex ) ;
kfree ( devlink_sb ) ;
}
EXPORT_SYMBOL_GPL ( devlink_sb_unregister ) ;
2017-03-28 18:24:10 +03:00
/**
* devlink_dpipe_headers_register - register dpipe headers
*
* @ devlink : devlink
* @ dpipe_headers : dpipe header array
*
* Register the headers supported by hardware .
*/
int devlink_dpipe_headers_register ( struct devlink * devlink ,
struct devlink_dpipe_headers * dpipe_headers )
{
mutex_lock ( & devlink_mutex ) ;
devlink - > dpipe_headers = dpipe_headers ;
mutex_unlock ( & devlink_mutex ) ;
return 0 ;
}
EXPORT_SYMBOL_GPL ( devlink_dpipe_headers_register ) ;
/**
* devlink_dpipe_headers_unregister - unregister dpipe headers
*
* @ devlink : devlink
*
* Unregister the headers supported by hardware .
*/
void devlink_dpipe_headers_unregister ( struct devlink * devlink )
{
mutex_lock ( & devlink_mutex ) ;
devlink - > dpipe_headers = NULL ;
mutex_unlock ( & devlink_mutex ) ;
}
EXPORT_SYMBOL_GPL ( devlink_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 ) ;
enabled = false ;
if ( table )
enabled = table - > counters_enabled ;
rcu_read_unlock ( ) ;
return enabled ;
}
EXPORT_SYMBOL_GPL ( devlink_dpipe_table_counter_enabled ) ;
/**
* devlink_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 devlink_dpipe_table_register ( struct devlink * devlink ,
const char * table_name ,
struct devlink_dpipe_table_ops * table_ops ,
2017-08-24 09:40:02 +03:00
void * priv , bool counter_control_extern )
2017-03-28 18:24:10 +03:00
{
struct devlink_dpipe_table * table ;
if ( devlink_dpipe_table_find ( & devlink - > dpipe_table_list , table_name ) )
return - EEXIST ;
2017-08-24 09:40:02 +03:00
if ( WARN_ON ( ! table_ops - > size_get ) )
return - EINVAL ;
2017-03-28 18:24:10 +03:00
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 ;
mutex_lock ( & devlink_mutex ) ;
list_add_tail_rcu ( & table - > list , & devlink - > dpipe_table_list ) ;
mutex_unlock ( & devlink_mutex ) ;
return 0 ;
}
EXPORT_SYMBOL_GPL ( devlink_dpipe_table_register ) ;
/**
* devlink_dpipe_table_unregister - unregister dpipe table
*
* @ devlink : devlink
* @ table_name : table name
*/
void devlink_dpipe_table_unregister ( struct devlink * devlink ,
const char * table_name )
{
struct devlink_dpipe_table * table ;
mutex_lock ( & devlink_mutex ) ;
table = devlink_dpipe_table_find ( & devlink - > dpipe_table_list ,
table_name ) ;
if ( ! table )
goto unlock ;
list_del_rcu ( & table - > list ) ;
mutex_unlock ( & devlink_mutex ) ;
kfree_rcu ( table , rcu ) ;
return ;
unlock :
mutex_unlock ( & devlink_mutex ) ;
}
EXPORT_SYMBOL_GPL ( devlink_dpipe_table_unregister ) ;
2016-02-26 19:32:23 +03:00
static int __init devlink_module_init ( void )
{
2016-10-24 15:40:03 +03:00
return genl_register_family ( & devlink_nl_family ) ;
2016-02-26 19:32:23 +03:00
}
static void __exit devlink_module_exit ( void )
{
genl_unregister_family ( & devlink_nl_family ) ;
}
module_init ( devlink_module_init ) ;
module_exit ( devlink_module_exit ) ;
MODULE_LICENSE ( " GPL v2 " ) ;
MODULE_AUTHOR ( " Jiri Pirko <jiri@mellanox.com> " ) ;
MODULE_DESCRIPTION ( " Network physical device Netlink interface " ) ;
MODULE_ALIAS_GENL_FAMILY ( DEVLINK_GENL_NAME ) ;