18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright (C) 2017 Netronome Systems, Inc. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * This software is licensed under the GNU General License Version 2, 58c2ecf20Sopenharmony_ci * June 1991 as shown in the file COPYING in the top-level directory of this 68c2ecf20Sopenharmony_ci * source tree. 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" 98c2ecf20Sopenharmony_ci * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, 108c2ecf20Sopenharmony_ci * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 118c2ecf20Sopenharmony_ci * FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE 128c2ecf20Sopenharmony_ci * OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME 138c2ecf20Sopenharmony_ci * THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 148c2ecf20Sopenharmony_ci */ 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#include <linux/debugfs.h> 178c2ecf20Sopenharmony_ci#include <linux/etherdevice.h> 188c2ecf20Sopenharmony_ci#include <linux/kernel.h> 198c2ecf20Sopenharmony_ci#include <linux/module.h> 208c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 218c2ecf20Sopenharmony_ci#include <linux/slab.h> 228c2ecf20Sopenharmony_ci#include <net/netlink.h> 238c2ecf20Sopenharmony_ci#include <net/pkt_cls.h> 248c2ecf20Sopenharmony_ci#include <net/rtnetlink.h> 258c2ecf20Sopenharmony_ci#include <net/udp_tunnel.h> 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci#include "netdevsim.h" 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_cistatic netdev_tx_t nsim_start_xmit(struct sk_buff *skb, struct net_device *dev) 308c2ecf20Sopenharmony_ci{ 318c2ecf20Sopenharmony_ci struct netdevsim *ns = netdev_priv(dev); 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci if (!nsim_ipsec_tx(ns, skb)) 348c2ecf20Sopenharmony_ci goto out; 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci u64_stats_update_begin(&ns->syncp); 378c2ecf20Sopenharmony_ci ns->tx_packets++; 388c2ecf20Sopenharmony_ci ns->tx_bytes += skb->len; 398c2ecf20Sopenharmony_ci u64_stats_update_end(&ns->syncp); 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ciout: 428c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 458c2ecf20Sopenharmony_ci} 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_cistatic void nsim_set_rx_mode(struct net_device *dev) 488c2ecf20Sopenharmony_ci{ 498c2ecf20Sopenharmony_ci} 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_cistatic int nsim_change_mtu(struct net_device *dev, int new_mtu) 528c2ecf20Sopenharmony_ci{ 538c2ecf20Sopenharmony_ci struct netdevsim *ns = netdev_priv(dev); 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci if (ns->xdp.prog && new_mtu > NSIM_XDP_MAX_MTU) 568c2ecf20Sopenharmony_ci return -EBUSY; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci dev->mtu = new_mtu; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci return 0; 618c2ecf20Sopenharmony_ci} 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_cistatic void 648c2ecf20Sopenharmony_cinsim_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) 658c2ecf20Sopenharmony_ci{ 668c2ecf20Sopenharmony_ci struct netdevsim *ns = netdev_priv(dev); 678c2ecf20Sopenharmony_ci unsigned int start; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci do { 708c2ecf20Sopenharmony_ci start = u64_stats_fetch_begin_irq(&ns->syncp); 718c2ecf20Sopenharmony_ci stats->tx_bytes = ns->tx_bytes; 728c2ecf20Sopenharmony_ci stats->tx_packets = ns->tx_packets; 738c2ecf20Sopenharmony_ci } while (u64_stats_fetch_retry_irq(&ns->syncp, start)); 748c2ecf20Sopenharmony_ci} 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_cistatic int 778c2ecf20Sopenharmony_cinsim_setup_tc_block_cb(enum tc_setup_type type, void *type_data, void *cb_priv) 788c2ecf20Sopenharmony_ci{ 798c2ecf20Sopenharmony_ci return nsim_bpf_setup_tc_block_cb(type, type_data, cb_priv); 808c2ecf20Sopenharmony_ci} 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_cistatic int nsim_set_vf_mac(struct net_device *dev, int vf, u8 *mac) 838c2ecf20Sopenharmony_ci{ 848c2ecf20Sopenharmony_ci struct netdevsim *ns = netdev_priv(dev); 858c2ecf20Sopenharmony_ci struct nsim_bus_dev *nsim_bus_dev = ns->nsim_bus_dev; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci /* Only refuse multicast addresses, zero address can mean unset/any. */ 888c2ecf20Sopenharmony_ci if (vf >= nsim_bus_dev->num_vfs || is_multicast_ether_addr(mac)) 898c2ecf20Sopenharmony_ci return -EINVAL; 908c2ecf20Sopenharmony_ci memcpy(nsim_bus_dev->vfconfigs[vf].vf_mac, mac, ETH_ALEN); 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci return 0; 938c2ecf20Sopenharmony_ci} 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_cistatic int nsim_set_vf_vlan(struct net_device *dev, int vf, 968c2ecf20Sopenharmony_ci u16 vlan, u8 qos, __be16 vlan_proto) 978c2ecf20Sopenharmony_ci{ 988c2ecf20Sopenharmony_ci struct netdevsim *ns = netdev_priv(dev); 998c2ecf20Sopenharmony_ci struct nsim_bus_dev *nsim_bus_dev = ns->nsim_bus_dev; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci if (vf >= nsim_bus_dev->num_vfs || vlan > 4095 || qos > 7) 1028c2ecf20Sopenharmony_ci return -EINVAL; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci nsim_bus_dev->vfconfigs[vf].vlan = vlan; 1058c2ecf20Sopenharmony_ci nsim_bus_dev->vfconfigs[vf].qos = qos; 1068c2ecf20Sopenharmony_ci nsim_bus_dev->vfconfigs[vf].vlan_proto = vlan_proto; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci return 0; 1098c2ecf20Sopenharmony_ci} 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_cistatic int nsim_set_vf_rate(struct net_device *dev, int vf, int min, int max) 1128c2ecf20Sopenharmony_ci{ 1138c2ecf20Sopenharmony_ci struct netdevsim *ns = netdev_priv(dev); 1148c2ecf20Sopenharmony_ci struct nsim_bus_dev *nsim_bus_dev = ns->nsim_bus_dev; 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci if (vf >= nsim_bus_dev->num_vfs) 1178c2ecf20Sopenharmony_ci return -EINVAL; 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci nsim_bus_dev->vfconfigs[vf].min_tx_rate = min; 1208c2ecf20Sopenharmony_ci nsim_bus_dev->vfconfigs[vf].max_tx_rate = max; 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci return 0; 1238c2ecf20Sopenharmony_ci} 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_cistatic int nsim_set_vf_spoofchk(struct net_device *dev, int vf, bool val) 1268c2ecf20Sopenharmony_ci{ 1278c2ecf20Sopenharmony_ci struct netdevsim *ns = netdev_priv(dev); 1288c2ecf20Sopenharmony_ci struct nsim_bus_dev *nsim_bus_dev = ns->nsim_bus_dev; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci if (vf >= nsim_bus_dev->num_vfs) 1318c2ecf20Sopenharmony_ci return -EINVAL; 1328c2ecf20Sopenharmony_ci nsim_bus_dev->vfconfigs[vf].spoofchk_enabled = val; 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci return 0; 1358c2ecf20Sopenharmony_ci} 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_cistatic int nsim_set_vf_rss_query_en(struct net_device *dev, int vf, bool val) 1388c2ecf20Sopenharmony_ci{ 1398c2ecf20Sopenharmony_ci struct netdevsim *ns = netdev_priv(dev); 1408c2ecf20Sopenharmony_ci struct nsim_bus_dev *nsim_bus_dev = ns->nsim_bus_dev; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci if (vf >= nsim_bus_dev->num_vfs) 1438c2ecf20Sopenharmony_ci return -EINVAL; 1448c2ecf20Sopenharmony_ci nsim_bus_dev->vfconfigs[vf].rss_query_enabled = val; 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci return 0; 1478c2ecf20Sopenharmony_ci} 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_cistatic int nsim_set_vf_trust(struct net_device *dev, int vf, bool val) 1508c2ecf20Sopenharmony_ci{ 1518c2ecf20Sopenharmony_ci struct netdevsim *ns = netdev_priv(dev); 1528c2ecf20Sopenharmony_ci struct nsim_bus_dev *nsim_bus_dev = ns->nsim_bus_dev; 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci if (vf >= nsim_bus_dev->num_vfs) 1558c2ecf20Sopenharmony_ci return -EINVAL; 1568c2ecf20Sopenharmony_ci nsim_bus_dev->vfconfigs[vf].trusted = val; 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci return 0; 1598c2ecf20Sopenharmony_ci} 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_cistatic int 1628c2ecf20Sopenharmony_cinsim_get_vf_config(struct net_device *dev, int vf, struct ifla_vf_info *ivi) 1638c2ecf20Sopenharmony_ci{ 1648c2ecf20Sopenharmony_ci struct netdevsim *ns = netdev_priv(dev); 1658c2ecf20Sopenharmony_ci struct nsim_bus_dev *nsim_bus_dev = ns->nsim_bus_dev; 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci if (vf >= nsim_bus_dev->num_vfs) 1688c2ecf20Sopenharmony_ci return -EINVAL; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci ivi->vf = vf; 1718c2ecf20Sopenharmony_ci ivi->linkstate = nsim_bus_dev->vfconfigs[vf].link_state; 1728c2ecf20Sopenharmony_ci ivi->min_tx_rate = nsim_bus_dev->vfconfigs[vf].min_tx_rate; 1738c2ecf20Sopenharmony_ci ivi->max_tx_rate = nsim_bus_dev->vfconfigs[vf].max_tx_rate; 1748c2ecf20Sopenharmony_ci ivi->vlan = nsim_bus_dev->vfconfigs[vf].vlan; 1758c2ecf20Sopenharmony_ci ivi->vlan_proto = nsim_bus_dev->vfconfigs[vf].vlan_proto; 1768c2ecf20Sopenharmony_ci ivi->qos = nsim_bus_dev->vfconfigs[vf].qos; 1778c2ecf20Sopenharmony_ci memcpy(&ivi->mac, nsim_bus_dev->vfconfigs[vf].vf_mac, ETH_ALEN); 1788c2ecf20Sopenharmony_ci ivi->spoofchk = nsim_bus_dev->vfconfigs[vf].spoofchk_enabled; 1798c2ecf20Sopenharmony_ci ivi->trusted = nsim_bus_dev->vfconfigs[vf].trusted; 1808c2ecf20Sopenharmony_ci ivi->rss_query_en = nsim_bus_dev->vfconfigs[vf].rss_query_enabled; 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci return 0; 1838c2ecf20Sopenharmony_ci} 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_cistatic int nsim_set_vf_link_state(struct net_device *dev, int vf, int state) 1868c2ecf20Sopenharmony_ci{ 1878c2ecf20Sopenharmony_ci struct netdevsim *ns = netdev_priv(dev); 1888c2ecf20Sopenharmony_ci struct nsim_bus_dev *nsim_bus_dev = ns->nsim_bus_dev; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci if (vf >= nsim_bus_dev->num_vfs) 1918c2ecf20Sopenharmony_ci return -EINVAL; 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci switch (state) { 1948c2ecf20Sopenharmony_ci case IFLA_VF_LINK_STATE_AUTO: 1958c2ecf20Sopenharmony_ci case IFLA_VF_LINK_STATE_ENABLE: 1968c2ecf20Sopenharmony_ci case IFLA_VF_LINK_STATE_DISABLE: 1978c2ecf20Sopenharmony_ci break; 1988c2ecf20Sopenharmony_ci default: 1998c2ecf20Sopenharmony_ci return -EINVAL; 2008c2ecf20Sopenharmony_ci } 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci nsim_bus_dev->vfconfigs[vf].link_state = state; 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci return 0; 2058c2ecf20Sopenharmony_ci} 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_cistatic LIST_HEAD(nsim_block_cb_list); 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_cistatic int 2108c2ecf20Sopenharmony_cinsim_setup_tc(struct net_device *dev, enum tc_setup_type type, void *type_data) 2118c2ecf20Sopenharmony_ci{ 2128c2ecf20Sopenharmony_ci struct netdevsim *ns = netdev_priv(dev); 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci switch (type) { 2158c2ecf20Sopenharmony_ci case TC_SETUP_BLOCK: 2168c2ecf20Sopenharmony_ci return flow_block_cb_setup_simple(type_data, 2178c2ecf20Sopenharmony_ci &nsim_block_cb_list, 2188c2ecf20Sopenharmony_ci nsim_setup_tc_block_cb, 2198c2ecf20Sopenharmony_ci ns, ns, true); 2208c2ecf20Sopenharmony_ci default: 2218c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 2228c2ecf20Sopenharmony_ci } 2238c2ecf20Sopenharmony_ci} 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_cistatic int 2268c2ecf20Sopenharmony_cinsim_set_features(struct net_device *dev, netdev_features_t features) 2278c2ecf20Sopenharmony_ci{ 2288c2ecf20Sopenharmony_ci struct netdevsim *ns = netdev_priv(dev); 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci if ((dev->features & NETIF_F_HW_TC) > (features & NETIF_F_HW_TC)) 2318c2ecf20Sopenharmony_ci return nsim_bpf_disable_tc(ns); 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci return 0; 2348c2ecf20Sopenharmony_ci} 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_cistatic struct devlink_port *nsim_get_devlink_port(struct net_device *dev) 2378c2ecf20Sopenharmony_ci{ 2388c2ecf20Sopenharmony_ci struct netdevsim *ns = netdev_priv(dev); 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci return &ns->nsim_dev_port->devlink_port; 2418c2ecf20Sopenharmony_ci} 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_cistatic const struct net_device_ops nsim_netdev_ops = { 2448c2ecf20Sopenharmony_ci .ndo_start_xmit = nsim_start_xmit, 2458c2ecf20Sopenharmony_ci .ndo_set_rx_mode = nsim_set_rx_mode, 2468c2ecf20Sopenharmony_ci .ndo_set_mac_address = eth_mac_addr, 2478c2ecf20Sopenharmony_ci .ndo_validate_addr = eth_validate_addr, 2488c2ecf20Sopenharmony_ci .ndo_change_mtu = nsim_change_mtu, 2498c2ecf20Sopenharmony_ci .ndo_get_stats64 = nsim_get_stats64, 2508c2ecf20Sopenharmony_ci .ndo_set_vf_mac = nsim_set_vf_mac, 2518c2ecf20Sopenharmony_ci .ndo_set_vf_vlan = nsim_set_vf_vlan, 2528c2ecf20Sopenharmony_ci .ndo_set_vf_rate = nsim_set_vf_rate, 2538c2ecf20Sopenharmony_ci .ndo_set_vf_spoofchk = nsim_set_vf_spoofchk, 2548c2ecf20Sopenharmony_ci .ndo_set_vf_trust = nsim_set_vf_trust, 2558c2ecf20Sopenharmony_ci .ndo_get_vf_config = nsim_get_vf_config, 2568c2ecf20Sopenharmony_ci .ndo_set_vf_link_state = nsim_set_vf_link_state, 2578c2ecf20Sopenharmony_ci .ndo_set_vf_rss_query_en = nsim_set_vf_rss_query_en, 2588c2ecf20Sopenharmony_ci .ndo_setup_tc = nsim_setup_tc, 2598c2ecf20Sopenharmony_ci .ndo_set_features = nsim_set_features, 2608c2ecf20Sopenharmony_ci .ndo_bpf = nsim_bpf, 2618c2ecf20Sopenharmony_ci .ndo_udp_tunnel_add = udp_tunnel_nic_add_port, 2628c2ecf20Sopenharmony_ci .ndo_udp_tunnel_del = udp_tunnel_nic_del_port, 2638c2ecf20Sopenharmony_ci .ndo_get_devlink_port = nsim_get_devlink_port, 2648c2ecf20Sopenharmony_ci}; 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_cistatic void nsim_setup(struct net_device *dev) 2678c2ecf20Sopenharmony_ci{ 2688c2ecf20Sopenharmony_ci ether_setup(dev); 2698c2ecf20Sopenharmony_ci eth_hw_addr_random(dev); 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci dev->tx_queue_len = 0; 2728c2ecf20Sopenharmony_ci dev->flags |= IFF_NOARP; 2738c2ecf20Sopenharmony_ci dev->flags &= ~IFF_MULTICAST; 2748c2ecf20Sopenharmony_ci dev->priv_flags |= IFF_LIVE_ADDR_CHANGE | 2758c2ecf20Sopenharmony_ci IFF_NO_QUEUE; 2768c2ecf20Sopenharmony_ci dev->features |= NETIF_F_HIGHDMA | 2778c2ecf20Sopenharmony_ci NETIF_F_SG | 2788c2ecf20Sopenharmony_ci NETIF_F_FRAGLIST | 2798c2ecf20Sopenharmony_ci NETIF_F_HW_CSUM | 2808c2ecf20Sopenharmony_ci NETIF_F_TSO; 2818c2ecf20Sopenharmony_ci dev->hw_features |= NETIF_F_HW_TC; 2828c2ecf20Sopenharmony_ci dev->max_mtu = ETH_MAX_MTU; 2838c2ecf20Sopenharmony_ci} 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_cistruct netdevsim * 2868c2ecf20Sopenharmony_cinsim_create(struct nsim_dev *nsim_dev, struct nsim_dev_port *nsim_dev_port) 2878c2ecf20Sopenharmony_ci{ 2888c2ecf20Sopenharmony_ci struct net_device *dev; 2898c2ecf20Sopenharmony_ci struct netdevsim *ns; 2908c2ecf20Sopenharmony_ci int err; 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci dev = alloc_netdev(sizeof(*ns), "eth%d", NET_NAME_UNKNOWN, nsim_setup); 2938c2ecf20Sopenharmony_ci if (!dev) 2948c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci dev_net_set(dev, nsim_dev_net(nsim_dev)); 2978c2ecf20Sopenharmony_ci ns = netdev_priv(dev); 2988c2ecf20Sopenharmony_ci ns->netdev = dev; 2998c2ecf20Sopenharmony_ci u64_stats_init(&ns->syncp); 3008c2ecf20Sopenharmony_ci ns->nsim_dev = nsim_dev; 3018c2ecf20Sopenharmony_ci ns->nsim_dev_port = nsim_dev_port; 3028c2ecf20Sopenharmony_ci ns->nsim_bus_dev = nsim_dev->nsim_bus_dev; 3038c2ecf20Sopenharmony_ci SET_NETDEV_DEV(dev, &ns->nsim_bus_dev->dev); 3048c2ecf20Sopenharmony_ci dev->netdev_ops = &nsim_netdev_ops; 3058c2ecf20Sopenharmony_ci nsim_ethtool_init(ns); 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci err = nsim_udp_tunnels_info_create(nsim_dev, dev); 3088c2ecf20Sopenharmony_ci if (err) 3098c2ecf20Sopenharmony_ci goto err_free_netdev; 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci rtnl_lock(); 3128c2ecf20Sopenharmony_ci err = nsim_bpf_init(ns); 3138c2ecf20Sopenharmony_ci if (err) 3148c2ecf20Sopenharmony_ci goto err_utn_destroy; 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci nsim_ipsec_init(ns); 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci err = register_netdevice(dev); 3198c2ecf20Sopenharmony_ci if (err) 3208c2ecf20Sopenharmony_ci goto err_ipsec_teardown; 3218c2ecf20Sopenharmony_ci rtnl_unlock(); 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci return ns; 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_cierr_ipsec_teardown: 3268c2ecf20Sopenharmony_ci nsim_ipsec_teardown(ns); 3278c2ecf20Sopenharmony_ci nsim_bpf_uninit(ns); 3288c2ecf20Sopenharmony_cierr_utn_destroy: 3298c2ecf20Sopenharmony_ci rtnl_unlock(); 3308c2ecf20Sopenharmony_ci nsim_udp_tunnels_info_destroy(dev); 3318c2ecf20Sopenharmony_cierr_free_netdev: 3328c2ecf20Sopenharmony_ci free_netdev(dev); 3338c2ecf20Sopenharmony_ci return ERR_PTR(err); 3348c2ecf20Sopenharmony_ci} 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_civoid nsim_destroy(struct netdevsim *ns) 3378c2ecf20Sopenharmony_ci{ 3388c2ecf20Sopenharmony_ci struct net_device *dev = ns->netdev; 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci rtnl_lock(); 3418c2ecf20Sopenharmony_ci unregister_netdevice(dev); 3428c2ecf20Sopenharmony_ci nsim_ipsec_teardown(ns); 3438c2ecf20Sopenharmony_ci nsim_bpf_uninit(ns); 3448c2ecf20Sopenharmony_ci rtnl_unlock(); 3458c2ecf20Sopenharmony_ci nsim_udp_tunnels_info_destroy(dev); 3468c2ecf20Sopenharmony_ci free_netdev(dev); 3478c2ecf20Sopenharmony_ci} 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_cistatic int nsim_validate(struct nlattr *tb[], struct nlattr *data[], 3508c2ecf20Sopenharmony_ci struct netlink_ext_ack *extack) 3518c2ecf20Sopenharmony_ci{ 3528c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Please use: echo \"[ID] [PORT_COUNT]\" > /sys/bus/netdevsim/new_device"); 3538c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 3548c2ecf20Sopenharmony_ci} 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_cistatic struct rtnl_link_ops nsim_link_ops __read_mostly = { 3578c2ecf20Sopenharmony_ci .kind = DRV_NAME, 3588c2ecf20Sopenharmony_ci .validate = nsim_validate, 3598c2ecf20Sopenharmony_ci}; 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_cistatic int __init nsim_module_init(void) 3628c2ecf20Sopenharmony_ci{ 3638c2ecf20Sopenharmony_ci int err; 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci err = nsim_dev_init(); 3668c2ecf20Sopenharmony_ci if (err) 3678c2ecf20Sopenharmony_ci return err; 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci err = nsim_bus_init(); 3708c2ecf20Sopenharmony_ci if (err) 3718c2ecf20Sopenharmony_ci goto err_dev_exit; 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci err = rtnl_link_register(&nsim_link_ops); 3748c2ecf20Sopenharmony_ci if (err) 3758c2ecf20Sopenharmony_ci goto err_bus_exit; 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci return 0; 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_cierr_bus_exit: 3808c2ecf20Sopenharmony_ci nsim_bus_exit(); 3818c2ecf20Sopenharmony_cierr_dev_exit: 3828c2ecf20Sopenharmony_ci nsim_dev_exit(); 3838c2ecf20Sopenharmony_ci return err; 3848c2ecf20Sopenharmony_ci} 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_cistatic void __exit nsim_module_exit(void) 3878c2ecf20Sopenharmony_ci{ 3888c2ecf20Sopenharmony_ci rtnl_link_unregister(&nsim_link_ops); 3898c2ecf20Sopenharmony_ci nsim_bus_exit(); 3908c2ecf20Sopenharmony_ci nsim_dev_exit(); 3918c2ecf20Sopenharmony_ci} 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_cimodule_init(nsim_module_init); 3948c2ecf20Sopenharmony_cimodule_exit(nsim_module_exit); 3958c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 3968c2ecf20Sopenharmony_ciMODULE_ALIAS_RTNL_LINK(DRV_NAME); 397