2017-12-01 15:08:58 -08:00
/*
* Copyright ( C ) 2017 Netronome Systems , Inc .
*
* 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 .
*/
2017-12-01 15:08:59 -08:00
# include <linux/debugfs.h>
2017-12-01 15:08:58 -08:00
# include <linux/etherdevice.h>
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/netdevice.h>
# include <linux/slab.h>
# include <net/netlink.h>
2017-12-01 15:08:59 -08:00
# include <net/pkt_cls.h>
2017-12-01 15:08:58 -08:00
# include <net/rtnetlink.h>
2020-07-09 17:42:48 -07:00
# include <net/udp_tunnel.h>
2017-12-01 15:08:58 -08:00
# include "netdevsim.h"
static netdev_tx_t nsim_start_xmit ( struct sk_buff * skb , struct net_device * dev )
{
struct netdevsim * ns = netdev_priv ( dev ) ;
2018-06-26 10:07:54 -07:00
if ( ! nsim_ipsec_tx ( ns , skb ) )
goto out ;
2017-12-01 15:08:58 -08:00
u64_stats_update_begin ( & ns - > syncp ) ;
ns - > tx_packets + + ;
ns - > tx_bytes + = skb - > len ;
u64_stats_update_end ( & ns - > syncp ) ;
2018-06-26 10:07:54 -07:00
out :
2017-12-01 15:08:58 -08:00
dev_kfree_skb ( skb ) ;
return NETDEV_TX_OK ;
}
static void nsim_set_rx_mode ( struct net_device * dev )
{
}
2017-12-01 15:08:59 -08:00
static int nsim_change_mtu ( struct net_device * dev , int new_mtu )
{
struct netdevsim * ns = netdev_priv ( dev ) ;
2018-07-11 20:36:42 -07:00
if ( ns - > xdp . prog & & new_mtu > NSIM_XDP_MAX_MTU )
2017-12-01 15:08:59 -08:00
return - EBUSY ;
dev - > mtu = new_mtu ;
return 0 ;
}
2017-12-01 15:08:58 -08:00
static void
nsim_get_stats64 ( struct net_device * dev , struct rtnl_link_stats64 * stats )
{
struct netdevsim * ns = netdev_priv ( dev ) ;
unsigned int start ;
do {
start = u64_stats_fetch_begin ( & ns - > syncp ) ;
stats - > tx_bytes = ns - > tx_bytes ;
stats - > tx_packets = ns - > tx_packets ;
} while ( u64_stats_fetch_retry ( & ns - > syncp , start ) ) ;
}
2017-12-01 15:08:59 -08:00
static int
nsim_setup_tc_block_cb ( enum tc_setup_type type , void * type_data , void * cb_priv )
{
return nsim_bpf_setup_tc_block_cb ( type , type_data , cb_priv ) ;
}
2017-12-01 15:09:01 -08:00
static int nsim_set_vf_mac ( struct net_device * dev , int vf , u8 * mac )
{
struct netdevsim * ns = netdev_priv ( dev ) ;
2019-04-25 15:59:45 +02:00
struct nsim_bus_dev * nsim_bus_dev = ns - > nsim_bus_dev ;
2017-12-01 15:09:01 -08:00
/* Only refuse multicast addresses, zero address can mean unset/any. */
2019-04-25 15:59:45 +02:00
if ( vf > = nsim_bus_dev - > num_vfs | | is_multicast_ether_addr ( mac ) )
2017-12-01 15:09:01 -08:00
return - EINVAL ;
2019-04-25 15:59:45 +02:00
memcpy ( nsim_bus_dev - > vfconfigs [ vf ] . vf_mac , mac , ETH_ALEN ) ;
2017-12-01 15:09:01 -08:00
return 0 ;
}
static int nsim_set_vf_vlan ( struct net_device * dev , int vf ,
u16 vlan , u8 qos , __be16 vlan_proto )
{
struct netdevsim * ns = netdev_priv ( dev ) ;
2019-04-25 15:59:45 +02:00
struct nsim_bus_dev * nsim_bus_dev = ns - > nsim_bus_dev ;
2017-12-01 15:09:01 -08:00
2019-04-25 15:59:45 +02:00
if ( vf > = nsim_bus_dev - > num_vfs | | vlan > 4095 | | qos > 7 )
2017-12-01 15:09:01 -08:00
return - EINVAL ;
2019-04-25 15:59:45 +02:00
nsim_bus_dev - > vfconfigs [ vf ] . vlan = vlan ;
nsim_bus_dev - > vfconfigs [ vf ] . qos = qos ;
nsim_bus_dev - > vfconfigs [ vf ] . vlan_proto = vlan_proto ;
2017-12-01 15:09:01 -08:00
return 0 ;
}
static int nsim_set_vf_rate ( struct net_device * dev , int vf , int min , int max )
{
struct netdevsim * ns = netdev_priv ( dev ) ;
2019-04-25 15:59:45 +02:00
struct nsim_bus_dev * nsim_bus_dev = ns - > nsim_bus_dev ;
2017-12-01 15:09:01 -08:00
2019-04-25 15:59:45 +02:00
if ( vf > = nsim_bus_dev - > num_vfs )
2017-12-01 15:09:01 -08:00
return - EINVAL ;
2019-04-25 15:59:45 +02:00
nsim_bus_dev - > vfconfigs [ vf ] . min_tx_rate = min ;
nsim_bus_dev - > vfconfigs [ vf ] . max_tx_rate = max ;
2017-12-01 15:09:01 -08:00
return 0 ;
}
static int nsim_set_vf_spoofchk ( struct net_device * dev , int vf , bool val )
{
struct netdevsim * ns = netdev_priv ( dev ) ;
2019-04-25 15:59:45 +02:00
struct nsim_bus_dev * nsim_bus_dev = ns - > nsim_bus_dev ;
2017-12-01 15:09:01 -08:00
2019-04-25 15:59:45 +02:00
if ( vf > = nsim_bus_dev - > num_vfs )
2017-12-01 15:09:01 -08:00
return - EINVAL ;
2019-04-25 15:59:45 +02:00
nsim_bus_dev - > vfconfigs [ vf ] . spoofchk_enabled = val ;
2017-12-01 15:09:01 -08:00
return 0 ;
}
static int nsim_set_vf_rss_query_en ( struct net_device * dev , int vf , bool val )
{
struct netdevsim * ns = netdev_priv ( dev ) ;
2019-04-25 15:59:45 +02:00
struct nsim_bus_dev * nsim_bus_dev = ns - > nsim_bus_dev ;
2017-12-01 15:09:01 -08:00
2019-04-25 15:59:45 +02:00
if ( vf > = nsim_bus_dev - > num_vfs )
2017-12-01 15:09:01 -08:00
return - EINVAL ;
2019-04-25 15:59:45 +02:00
nsim_bus_dev - > vfconfigs [ vf ] . rss_query_enabled = val ;
2017-12-01 15:09:01 -08:00
return 0 ;
}
static int nsim_set_vf_trust ( struct net_device * dev , int vf , bool val )
{
struct netdevsim * ns = netdev_priv ( dev ) ;
2019-04-25 15:59:45 +02:00
struct nsim_bus_dev * nsim_bus_dev = ns - > nsim_bus_dev ;
2017-12-01 15:09:01 -08:00
2019-04-25 15:59:45 +02:00
if ( vf > = nsim_bus_dev - > num_vfs )
2017-12-01 15:09:01 -08:00
return - EINVAL ;
2019-04-25 15:59:45 +02:00
nsim_bus_dev - > vfconfigs [ vf ] . trusted = val ;
2017-12-01 15:09:01 -08:00
return 0 ;
}
static int
nsim_get_vf_config ( struct net_device * dev , int vf , struct ifla_vf_info * ivi )
{
struct netdevsim * ns = netdev_priv ( dev ) ;
2019-04-25 15:59:45 +02:00
struct nsim_bus_dev * nsim_bus_dev = ns - > nsim_bus_dev ;
2017-12-01 15:09:01 -08:00
2019-04-25 15:59:45 +02:00
if ( vf > = nsim_bus_dev - > num_vfs )
2017-12-01 15:09:01 -08:00
return - EINVAL ;
ivi - > vf = vf ;
2019-04-25 15:59:45 +02:00
ivi - > linkstate = nsim_bus_dev - > vfconfigs [ vf ] . link_state ;
ivi - > min_tx_rate = nsim_bus_dev - > vfconfigs [ vf ] . min_tx_rate ;
ivi - > max_tx_rate = nsim_bus_dev - > vfconfigs [ vf ] . max_tx_rate ;
ivi - > vlan = nsim_bus_dev - > vfconfigs [ vf ] . vlan ;
ivi - > vlan_proto = nsim_bus_dev - > vfconfigs [ vf ] . vlan_proto ;
ivi - > qos = nsim_bus_dev - > vfconfigs [ vf ] . qos ;
memcpy ( & ivi - > mac , nsim_bus_dev - > vfconfigs [ vf ] . vf_mac , ETH_ALEN ) ;
ivi - > spoofchk = nsim_bus_dev - > vfconfigs [ vf ] . spoofchk_enabled ;
ivi - > trusted = nsim_bus_dev - > vfconfigs [ vf ] . trusted ;
ivi - > rss_query_en = nsim_bus_dev - > vfconfigs [ vf ] . rss_query_enabled ;
2017-12-01 15:09:01 -08:00
return 0 ;
}
static int nsim_set_vf_link_state ( struct net_device * dev , int vf , int state )
{
struct netdevsim * ns = netdev_priv ( dev ) ;
2019-04-25 15:59:45 +02:00
struct nsim_bus_dev * nsim_bus_dev = ns - > nsim_bus_dev ;
2017-12-01 15:09:01 -08:00
2019-04-25 15:59:45 +02:00
if ( vf > = nsim_bus_dev - > num_vfs )
2017-12-01 15:09:01 -08:00
return - EINVAL ;
switch ( state ) {
case IFLA_VF_LINK_STATE_AUTO :
case IFLA_VF_LINK_STATE_ENABLE :
case IFLA_VF_LINK_STATE_DISABLE :
break ;
default :
return - EINVAL ;
}
2019-04-25 15:59:45 +02:00
nsim_bus_dev - > vfconfigs [ vf ] . link_state = state ;
2017-12-01 15:09:01 -08:00
return 0 ;
}
2019-07-09 22:55:46 +02:00
static LIST_HEAD ( nsim_block_cb_list ) ;
2017-12-01 15:08:59 -08:00
static int
nsim_setup_tc ( struct net_device * dev , enum tc_setup_type type , void * type_data )
{
2019-07-09 22:55:39 +02:00
struct netdevsim * ns = netdev_priv ( dev ) ;
2017-12-01 15:08:59 -08:00
switch ( type ) {
case TC_SETUP_BLOCK :
2019-07-09 22:55:46 +02:00
return flow_block_cb_setup_simple ( type_data ,
& nsim_block_cb_list ,
2019-07-09 22:55:39 +02:00
nsim_setup_tc_block_cb ,
ns , ns , true ) ;
2017-12-01 15:08:59 -08:00
default :
return - EOPNOTSUPP ;
}
}
static int
nsim_set_features ( struct net_device * dev , netdev_features_t features )
{
struct netdevsim * ns = netdev_priv ( dev ) ;
if ( ( dev - > features & NETIF_F_HW_TC ) > ( features & NETIF_F_HW_TC ) )
return nsim_bpf_disable_tc ( ns ) ;
return 0 ;
}
2019-04-25 15:59:56 +02:00
static struct devlink_port * nsim_get_devlink_port ( struct net_device * dev )
{
struct netdevsim * ns = netdev_priv ( dev ) ;
return & ns - > nsim_dev_port - > devlink_port ;
}
2017-12-01 15:08:58 -08:00
static const struct net_device_ops nsim_netdev_ops = {
. ndo_start_xmit = nsim_start_xmit ,
. ndo_set_rx_mode = nsim_set_rx_mode ,
. ndo_set_mac_address = eth_mac_addr ,
. ndo_validate_addr = eth_validate_addr ,
2017-12-01 15:08:59 -08:00
. ndo_change_mtu = nsim_change_mtu ,
2017-12-01 15:08:58 -08:00
. ndo_get_stats64 = nsim_get_stats64 ,
2017-12-01 15:09:01 -08:00
. ndo_set_vf_mac = nsim_set_vf_mac ,
. ndo_set_vf_vlan = nsim_set_vf_vlan ,
. ndo_set_vf_rate = nsim_set_vf_rate ,
. ndo_set_vf_spoofchk = nsim_set_vf_spoofchk ,
. ndo_set_vf_trust = nsim_set_vf_trust ,
. ndo_get_vf_config = nsim_get_vf_config ,
. ndo_set_vf_link_state = nsim_set_vf_link_state ,
. ndo_set_vf_rss_query_en = nsim_set_vf_rss_query_en ,
2017-12-01 15:08:59 -08:00
. ndo_setup_tc = nsim_setup_tc ,
. ndo_set_features = nsim_set_features ,
. ndo_bpf = nsim_bpf ,
2020-07-09 17:42:48 -07:00
. ndo_udp_tunnel_add = udp_tunnel_nic_add_port ,
. ndo_udp_tunnel_del = udp_tunnel_nic_del_port ,
2019-04-25 15:59:56 +02:00
. ndo_get_devlink_port = nsim_get_devlink_port ,
2017-12-01 15:08:58 -08:00
} ;
static void nsim_setup ( struct net_device * dev )
{
ether_setup ( dev ) ;
eth_hw_addr_random ( dev ) ;
dev - > tx_queue_len = 0 ;
dev - > flags | = IFF_NOARP ;
dev - > flags & = ~ IFF_MULTICAST ;
dev - > priv_flags | = IFF_LIVE_ADDR_CHANGE |
IFF_NO_QUEUE ;
dev - > features | = NETIF_F_HIGHDMA |
NETIF_F_SG |
NETIF_F_FRAGLIST |
NETIF_F_HW_CSUM |
NETIF_F_TSO ;
2017-12-01 15:08:59 -08:00
dev - > hw_features | = NETIF_F_HW_TC ;
2017-12-01 15:08:58 -08:00
dev - > max_mtu = ETH_MAX_MTU ;
}
2019-04-25 15:59:55 +02:00
struct netdevsim *
nsim_create ( struct nsim_dev * nsim_dev , struct nsim_dev_port * nsim_dev_port )
2018-07-17 10:53:20 -07:00
{
2019-04-25 15:59:55 +02:00
struct net_device * dev ;
struct netdevsim * ns ;
2019-04-12 14:49:26 +02:00
int err ;
2018-07-17 10:53:20 -07:00
2019-04-25 15:59:55 +02:00
dev = alloc_netdev ( sizeof ( * ns ) , " eth%d " , NET_NAME_UNKNOWN , nsim_setup ) ;
if ( ! dev )
return ERR_PTR ( - ENOMEM ) ;
2019-04-25 15:59:41 +02:00
2019-10-03 11:49:37 +02:00
dev_net_set ( dev , nsim_dev_net ( nsim_dev ) ) ;
2019-04-25 15:59:55 +02:00
ns = netdev_priv ( dev ) ;
ns - > netdev = dev ;
ns - > nsim_dev = nsim_dev ;
ns - > nsim_dev_port = nsim_dev_port ;
ns - > nsim_bus_dev = nsim_dev - > nsim_bus_dev ;
2019-04-25 15:59:45 +02:00
SET_NETDEV_DEV ( dev , & ns - > nsim_bus_dev - > dev ) ;
2019-04-25 15:59:55 +02:00
dev - > netdev_ops = & nsim_netdev_ops ;
2019-04-25 15:59:41 +02:00
2020-07-09 17:42:48 -07:00
err = nsim_udp_tunnels_info_create ( nsim_dev , dev ) ;
if ( err )
goto err_free_netdev ;
2019-04-25 15:59:55 +02:00
rtnl_lock ( ) ;
err = nsim_bpf_init ( ns ) ;
if ( err )
2020-07-09 17:42:48 -07:00
goto err_utn_destroy ;
2019-04-25 15:59:55 +02:00
nsim_ipsec_init ( ns ) ;
2019-04-25 15:59:42 +02:00
err = register_netdevice ( dev ) ;
if ( err )
2019-04-25 15:59:55 +02:00
goto err_ipsec_teardown ;
rtnl_unlock ( ) ;
2019-04-12 14:49:26 +02:00
2019-04-25 15:59:55 +02:00
return ns ;
err_ipsec_teardown :
nsim_ipsec_teardown ( ns ) ;
nsim_bpf_uninit ( ns ) ;
2020-07-09 17:42:48 -07:00
err_utn_destroy :
2019-04-25 15:59:55 +02:00
rtnl_unlock ( ) ;
2020-07-09 17:42:48 -07:00
nsim_udp_tunnels_info_destroy ( dev ) ;
2019-04-25 15:59:55 +02:00
err_free_netdev :
free_netdev ( dev ) ;
return ERR_PTR ( err ) ;
}
void nsim_destroy ( struct netdevsim * ns )
{
struct net_device * dev = ns - > netdev ;
rtnl_lock ( ) ;
unregister_netdevice ( dev ) ;
nsim_ipsec_teardown ( ns ) ;
nsim_bpf_uninit ( ns ) ;
rtnl_unlock ( ) ;
2020-07-09 17:42:48 -07:00
nsim_udp_tunnels_info_destroy ( dev ) ;
2019-04-25 15:59:55 +02:00
free_netdev ( dev ) ;
}
static int nsim_validate ( struct nlattr * tb [ ] , struct nlattr * data [ ] ,
struct netlink_ext_ack * extack )
{
NL_SET_ERR_MSG_MOD ( extack , " Please use: echo \" [ID] [PORT_COUNT] \" > /sys/bus/netdevsim/new_device " ) ;
return - EOPNOTSUPP ;
2018-07-17 10:53:20 -07:00
}
2017-12-01 15:08:58 -08:00
static struct rtnl_link_ops nsim_link_ops __read_mostly = {
. kind = DRV_NAME ,
. validate = nsim_validate ,
} ;
static int __init nsim_module_init ( void )
{
2017-12-01 15:08:59 -08:00
int err ;
2019-04-25 15:59:50 +02:00
err = nsim_dev_init ( ) ;
2019-04-12 14:49:26 +02:00
if ( err )
2019-04-25 15:59:52 +02:00
return err ;
2018-07-17 10:53:20 -07:00
2019-04-25 15:59:44 +02:00
err = nsim_bus_init ( ) ;
2017-12-01 15:08:59 -08:00
if ( err )
2019-04-25 15:59:50 +02:00
goto err_dev_exit ;
2017-12-01 15:08:59 -08:00
2019-08-06 12:15:17 -07:00
err = rtnl_link_register ( & nsim_link_ops ) ;
if ( err )
2019-10-03 11:49:26 +02:00
goto err_bus_exit ;
2019-08-06 12:15:17 -07:00
2017-12-01 15:08:59 -08:00
return 0 ;
2019-04-25 15:59:44 +02:00
err_bus_exit :
nsim_bus_exit ( ) ;
2019-04-25 15:59:50 +02:00
err_dev_exit :
nsim_dev_exit ( ) ;
2017-12-01 15:08:59 -08:00
return err ;
2017-12-01 15:08:58 -08:00
}
static void __exit nsim_module_exit ( void )
{
rtnl_link_unregister ( & nsim_link_ops ) ;
2019-04-25 15:59:44 +02:00
nsim_bus_exit ( ) ;
2019-04-25 15:59:50 +02:00
nsim_dev_exit ( ) ;
2017-12-01 15:08:58 -08:00
}
module_init ( nsim_module_init ) ;
module_exit ( nsim_module_exit ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_ALIAS_RTNL_LINK ( DRV_NAME ) ;