162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Copyright (C) 2017 Netronome Systems, Inc. 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * This software is licensed under the GNU General License Version 2, 562306a36Sopenharmony_ci * June 1991 as shown in the file COPYING in the top-level directory of this 662306a36Sopenharmony_ci * source tree. 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" 962306a36Sopenharmony_ci * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, 1062306a36Sopenharmony_ci * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 1162306a36Sopenharmony_ci * FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE 1262306a36Sopenharmony_ci * OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME 1362306a36Sopenharmony_ci * THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 1462306a36Sopenharmony_ci */ 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#include <linux/debugfs.h> 1762306a36Sopenharmony_ci#include <linux/etherdevice.h> 1862306a36Sopenharmony_ci#include <linux/kernel.h> 1962306a36Sopenharmony_ci#include <linux/module.h> 2062306a36Sopenharmony_ci#include <linux/netdevice.h> 2162306a36Sopenharmony_ci#include <linux/slab.h> 2262306a36Sopenharmony_ci#include <net/netlink.h> 2362306a36Sopenharmony_ci#include <net/pkt_cls.h> 2462306a36Sopenharmony_ci#include <net/rtnetlink.h> 2562306a36Sopenharmony_ci#include <net/udp_tunnel.h> 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci#include "netdevsim.h" 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_cistatic netdev_tx_t nsim_start_xmit(struct sk_buff *skb, struct net_device *dev) 3062306a36Sopenharmony_ci{ 3162306a36Sopenharmony_ci struct netdevsim *ns = netdev_priv(dev); 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci if (!nsim_ipsec_tx(ns, skb)) 3462306a36Sopenharmony_ci goto out; 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci u64_stats_update_begin(&ns->syncp); 3762306a36Sopenharmony_ci ns->tx_packets++; 3862306a36Sopenharmony_ci ns->tx_bytes += skb->len; 3962306a36Sopenharmony_ci u64_stats_update_end(&ns->syncp); 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ciout: 4262306a36Sopenharmony_ci dev_kfree_skb(skb); 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci return NETDEV_TX_OK; 4562306a36Sopenharmony_ci} 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_cistatic void nsim_set_rx_mode(struct net_device *dev) 4862306a36Sopenharmony_ci{ 4962306a36Sopenharmony_ci} 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_cistatic int nsim_change_mtu(struct net_device *dev, int new_mtu) 5262306a36Sopenharmony_ci{ 5362306a36Sopenharmony_ci struct netdevsim *ns = netdev_priv(dev); 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci if (ns->xdp.prog && new_mtu > NSIM_XDP_MAX_MTU) 5662306a36Sopenharmony_ci return -EBUSY; 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci dev->mtu = new_mtu; 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci return 0; 6162306a36Sopenharmony_ci} 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_cistatic void 6462306a36Sopenharmony_cinsim_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) 6562306a36Sopenharmony_ci{ 6662306a36Sopenharmony_ci struct netdevsim *ns = netdev_priv(dev); 6762306a36Sopenharmony_ci unsigned int start; 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci do { 7062306a36Sopenharmony_ci start = u64_stats_fetch_begin(&ns->syncp); 7162306a36Sopenharmony_ci stats->tx_bytes = ns->tx_bytes; 7262306a36Sopenharmony_ci stats->tx_packets = ns->tx_packets; 7362306a36Sopenharmony_ci } while (u64_stats_fetch_retry(&ns->syncp, start)); 7462306a36Sopenharmony_ci} 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_cistatic int 7762306a36Sopenharmony_cinsim_setup_tc_block_cb(enum tc_setup_type type, void *type_data, void *cb_priv) 7862306a36Sopenharmony_ci{ 7962306a36Sopenharmony_ci return nsim_bpf_setup_tc_block_cb(type, type_data, cb_priv); 8062306a36Sopenharmony_ci} 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_cistatic int nsim_set_vf_mac(struct net_device *dev, int vf, u8 *mac) 8362306a36Sopenharmony_ci{ 8462306a36Sopenharmony_ci struct netdevsim *ns = netdev_priv(dev); 8562306a36Sopenharmony_ci struct nsim_dev *nsim_dev = ns->nsim_dev; 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci /* Only refuse multicast addresses, zero address can mean unset/any. */ 8862306a36Sopenharmony_ci if (vf >= nsim_dev_get_vfs(nsim_dev) || is_multicast_ether_addr(mac)) 8962306a36Sopenharmony_ci return -EINVAL; 9062306a36Sopenharmony_ci memcpy(nsim_dev->vfconfigs[vf].vf_mac, mac, ETH_ALEN); 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci return 0; 9362306a36Sopenharmony_ci} 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_cistatic int nsim_set_vf_vlan(struct net_device *dev, int vf, 9662306a36Sopenharmony_ci u16 vlan, u8 qos, __be16 vlan_proto) 9762306a36Sopenharmony_ci{ 9862306a36Sopenharmony_ci struct netdevsim *ns = netdev_priv(dev); 9962306a36Sopenharmony_ci struct nsim_dev *nsim_dev = ns->nsim_dev; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci if (vf >= nsim_dev_get_vfs(nsim_dev) || vlan > 4095 || qos > 7) 10262306a36Sopenharmony_ci return -EINVAL; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci nsim_dev->vfconfigs[vf].vlan = vlan; 10562306a36Sopenharmony_ci nsim_dev->vfconfigs[vf].qos = qos; 10662306a36Sopenharmony_ci nsim_dev->vfconfigs[vf].vlan_proto = vlan_proto; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci return 0; 10962306a36Sopenharmony_ci} 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_cistatic int nsim_set_vf_rate(struct net_device *dev, int vf, int min, int max) 11262306a36Sopenharmony_ci{ 11362306a36Sopenharmony_ci struct netdevsim *ns = netdev_priv(dev); 11462306a36Sopenharmony_ci struct nsim_dev *nsim_dev = ns->nsim_dev; 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci if (nsim_esw_mode_is_switchdev(ns->nsim_dev)) { 11762306a36Sopenharmony_ci pr_err("Not supported in switchdev mode. Please use devlink API.\n"); 11862306a36Sopenharmony_ci return -EOPNOTSUPP; 11962306a36Sopenharmony_ci } 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci if (vf >= nsim_dev_get_vfs(nsim_dev)) 12262306a36Sopenharmony_ci return -EINVAL; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci nsim_dev->vfconfigs[vf].min_tx_rate = min; 12562306a36Sopenharmony_ci nsim_dev->vfconfigs[vf].max_tx_rate = max; 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci return 0; 12862306a36Sopenharmony_ci} 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_cistatic int nsim_set_vf_spoofchk(struct net_device *dev, int vf, bool val) 13162306a36Sopenharmony_ci{ 13262306a36Sopenharmony_ci struct netdevsim *ns = netdev_priv(dev); 13362306a36Sopenharmony_ci struct nsim_dev *nsim_dev = ns->nsim_dev; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci if (vf >= nsim_dev_get_vfs(nsim_dev)) 13662306a36Sopenharmony_ci return -EINVAL; 13762306a36Sopenharmony_ci nsim_dev->vfconfigs[vf].spoofchk_enabled = val; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci return 0; 14062306a36Sopenharmony_ci} 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_cistatic int nsim_set_vf_rss_query_en(struct net_device *dev, int vf, bool val) 14362306a36Sopenharmony_ci{ 14462306a36Sopenharmony_ci struct netdevsim *ns = netdev_priv(dev); 14562306a36Sopenharmony_ci struct nsim_dev *nsim_dev = ns->nsim_dev; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci if (vf >= nsim_dev_get_vfs(nsim_dev)) 14862306a36Sopenharmony_ci return -EINVAL; 14962306a36Sopenharmony_ci nsim_dev->vfconfigs[vf].rss_query_enabled = val; 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci return 0; 15262306a36Sopenharmony_ci} 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_cistatic int nsim_set_vf_trust(struct net_device *dev, int vf, bool val) 15562306a36Sopenharmony_ci{ 15662306a36Sopenharmony_ci struct netdevsim *ns = netdev_priv(dev); 15762306a36Sopenharmony_ci struct nsim_dev *nsim_dev = ns->nsim_dev; 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci if (vf >= nsim_dev_get_vfs(nsim_dev)) 16062306a36Sopenharmony_ci return -EINVAL; 16162306a36Sopenharmony_ci nsim_dev->vfconfigs[vf].trusted = val; 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci return 0; 16462306a36Sopenharmony_ci} 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_cistatic int 16762306a36Sopenharmony_cinsim_get_vf_config(struct net_device *dev, int vf, struct ifla_vf_info *ivi) 16862306a36Sopenharmony_ci{ 16962306a36Sopenharmony_ci struct netdevsim *ns = netdev_priv(dev); 17062306a36Sopenharmony_ci struct nsim_dev *nsim_dev = ns->nsim_dev; 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci if (vf >= nsim_dev_get_vfs(nsim_dev)) 17362306a36Sopenharmony_ci return -EINVAL; 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci ivi->vf = vf; 17662306a36Sopenharmony_ci ivi->linkstate = nsim_dev->vfconfigs[vf].link_state; 17762306a36Sopenharmony_ci ivi->min_tx_rate = nsim_dev->vfconfigs[vf].min_tx_rate; 17862306a36Sopenharmony_ci ivi->max_tx_rate = nsim_dev->vfconfigs[vf].max_tx_rate; 17962306a36Sopenharmony_ci ivi->vlan = nsim_dev->vfconfigs[vf].vlan; 18062306a36Sopenharmony_ci ivi->vlan_proto = nsim_dev->vfconfigs[vf].vlan_proto; 18162306a36Sopenharmony_ci ivi->qos = nsim_dev->vfconfigs[vf].qos; 18262306a36Sopenharmony_ci memcpy(&ivi->mac, nsim_dev->vfconfigs[vf].vf_mac, ETH_ALEN); 18362306a36Sopenharmony_ci ivi->spoofchk = nsim_dev->vfconfigs[vf].spoofchk_enabled; 18462306a36Sopenharmony_ci ivi->trusted = nsim_dev->vfconfigs[vf].trusted; 18562306a36Sopenharmony_ci ivi->rss_query_en = nsim_dev->vfconfigs[vf].rss_query_enabled; 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci return 0; 18862306a36Sopenharmony_ci} 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_cistatic int nsim_set_vf_link_state(struct net_device *dev, int vf, int state) 19162306a36Sopenharmony_ci{ 19262306a36Sopenharmony_ci struct netdevsim *ns = netdev_priv(dev); 19362306a36Sopenharmony_ci struct nsim_dev *nsim_dev = ns->nsim_dev; 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci if (vf >= nsim_dev_get_vfs(nsim_dev)) 19662306a36Sopenharmony_ci return -EINVAL; 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci switch (state) { 19962306a36Sopenharmony_ci case IFLA_VF_LINK_STATE_AUTO: 20062306a36Sopenharmony_ci case IFLA_VF_LINK_STATE_ENABLE: 20162306a36Sopenharmony_ci case IFLA_VF_LINK_STATE_DISABLE: 20262306a36Sopenharmony_ci break; 20362306a36Sopenharmony_ci default: 20462306a36Sopenharmony_ci return -EINVAL; 20562306a36Sopenharmony_ci } 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci nsim_dev->vfconfigs[vf].link_state = state; 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci return 0; 21062306a36Sopenharmony_ci} 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_cistatic void nsim_taprio_stats(struct tc_taprio_qopt_stats *stats) 21362306a36Sopenharmony_ci{ 21462306a36Sopenharmony_ci stats->window_drops = 0; 21562306a36Sopenharmony_ci stats->tx_overruns = 0; 21662306a36Sopenharmony_ci} 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_cistatic int nsim_setup_tc_taprio(struct net_device *dev, 21962306a36Sopenharmony_ci struct tc_taprio_qopt_offload *offload) 22062306a36Sopenharmony_ci{ 22162306a36Sopenharmony_ci int err = 0; 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci switch (offload->cmd) { 22462306a36Sopenharmony_ci case TAPRIO_CMD_REPLACE: 22562306a36Sopenharmony_ci case TAPRIO_CMD_DESTROY: 22662306a36Sopenharmony_ci break; 22762306a36Sopenharmony_ci case TAPRIO_CMD_STATS: 22862306a36Sopenharmony_ci nsim_taprio_stats(&offload->stats); 22962306a36Sopenharmony_ci break; 23062306a36Sopenharmony_ci default: 23162306a36Sopenharmony_ci err = -EOPNOTSUPP; 23262306a36Sopenharmony_ci } 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci return err; 23562306a36Sopenharmony_ci} 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_cistatic LIST_HEAD(nsim_block_cb_list); 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_cistatic int 24062306a36Sopenharmony_cinsim_setup_tc(struct net_device *dev, enum tc_setup_type type, void *type_data) 24162306a36Sopenharmony_ci{ 24262306a36Sopenharmony_ci struct netdevsim *ns = netdev_priv(dev); 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci switch (type) { 24562306a36Sopenharmony_ci case TC_SETUP_QDISC_TAPRIO: 24662306a36Sopenharmony_ci return nsim_setup_tc_taprio(dev, type_data); 24762306a36Sopenharmony_ci case TC_SETUP_BLOCK: 24862306a36Sopenharmony_ci return flow_block_cb_setup_simple(type_data, 24962306a36Sopenharmony_ci &nsim_block_cb_list, 25062306a36Sopenharmony_ci nsim_setup_tc_block_cb, 25162306a36Sopenharmony_ci ns, ns, true); 25262306a36Sopenharmony_ci default: 25362306a36Sopenharmony_ci return -EOPNOTSUPP; 25462306a36Sopenharmony_ci } 25562306a36Sopenharmony_ci} 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_cistatic int 25862306a36Sopenharmony_cinsim_set_features(struct net_device *dev, netdev_features_t features) 25962306a36Sopenharmony_ci{ 26062306a36Sopenharmony_ci struct netdevsim *ns = netdev_priv(dev); 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci if ((dev->features & NETIF_F_HW_TC) > (features & NETIF_F_HW_TC)) 26362306a36Sopenharmony_ci return nsim_bpf_disable_tc(ns); 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci return 0; 26662306a36Sopenharmony_ci} 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_cistatic const struct net_device_ops nsim_netdev_ops = { 26962306a36Sopenharmony_ci .ndo_start_xmit = nsim_start_xmit, 27062306a36Sopenharmony_ci .ndo_set_rx_mode = nsim_set_rx_mode, 27162306a36Sopenharmony_ci .ndo_set_mac_address = eth_mac_addr, 27262306a36Sopenharmony_ci .ndo_validate_addr = eth_validate_addr, 27362306a36Sopenharmony_ci .ndo_change_mtu = nsim_change_mtu, 27462306a36Sopenharmony_ci .ndo_get_stats64 = nsim_get_stats64, 27562306a36Sopenharmony_ci .ndo_set_vf_mac = nsim_set_vf_mac, 27662306a36Sopenharmony_ci .ndo_set_vf_vlan = nsim_set_vf_vlan, 27762306a36Sopenharmony_ci .ndo_set_vf_rate = nsim_set_vf_rate, 27862306a36Sopenharmony_ci .ndo_set_vf_spoofchk = nsim_set_vf_spoofchk, 27962306a36Sopenharmony_ci .ndo_set_vf_trust = nsim_set_vf_trust, 28062306a36Sopenharmony_ci .ndo_get_vf_config = nsim_get_vf_config, 28162306a36Sopenharmony_ci .ndo_set_vf_link_state = nsim_set_vf_link_state, 28262306a36Sopenharmony_ci .ndo_set_vf_rss_query_en = nsim_set_vf_rss_query_en, 28362306a36Sopenharmony_ci .ndo_setup_tc = nsim_setup_tc, 28462306a36Sopenharmony_ci .ndo_set_features = nsim_set_features, 28562306a36Sopenharmony_ci .ndo_bpf = nsim_bpf, 28662306a36Sopenharmony_ci}; 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_cistatic const struct net_device_ops nsim_vf_netdev_ops = { 28962306a36Sopenharmony_ci .ndo_start_xmit = nsim_start_xmit, 29062306a36Sopenharmony_ci .ndo_set_rx_mode = nsim_set_rx_mode, 29162306a36Sopenharmony_ci .ndo_set_mac_address = eth_mac_addr, 29262306a36Sopenharmony_ci .ndo_validate_addr = eth_validate_addr, 29362306a36Sopenharmony_ci .ndo_change_mtu = nsim_change_mtu, 29462306a36Sopenharmony_ci .ndo_get_stats64 = nsim_get_stats64, 29562306a36Sopenharmony_ci .ndo_setup_tc = nsim_setup_tc, 29662306a36Sopenharmony_ci .ndo_set_features = nsim_set_features, 29762306a36Sopenharmony_ci}; 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_cistatic void nsim_setup(struct net_device *dev) 30062306a36Sopenharmony_ci{ 30162306a36Sopenharmony_ci ether_setup(dev); 30262306a36Sopenharmony_ci eth_hw_addr_random(dev); 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci dev->tx_queue_len = 0; 30562306a36Sopenharmony_ci dev->flags |= IFF_NOARP; 30662306a36Sopenharmony_ci dev->flags &= ~IFF_MULTICAST; 30762306a36Sopenharmony_ci dev->priv_flags |= IFF_LIVE_ADDR_CHANGE | 30862306a36Sopenharmony_ci IFF_NO_QUEUE; 30962306a36Sopenharmony_ci dev->features |= NETIF_F_HIGHDMA | 31062306a36Sopenharmony_ci NETIF_F_SG | 31162306a36Sopenharmony_ci NETIF_F_FRAGLIST | 31262306a36Sopenharmony_ci NETIF_F_HW_CSUM | 31362306a36Sopenharmony_ci NETIF_F_TSO; 31462306a36Sopenharmony_ci dev->hw_features |= NETIF_F_HW_TC; 31562306a36Sopenharmony_ci dev->max_mtu = ETH_MAX_MTU; 31662306a36Sopenharmony_ci dev->xdp_features = NETDEV_XDP_ACT_HW_OFFLOAD; 31762306a36Sopenharmony_ci} 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_cistatic int nsim_init_netdevsim(struct netdevsim *ns) 32062306a36Sopenharmony_ci{ 32162306a36Sopenharmony_ci struct mock_phc *phc; 32262306a36Sopenharmony_ci int err; 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci phc = mock_phc_create(&ns->nsim_bus_dev->dev); 32562306a36Sopenharmony_ci if (IS_ERR(phc)) 32662306a36Sopenharmony_ci return PTR_ERR(phc); 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci ns->phc = phc; 32962306a36Sopenharmony_ci ns->netdev->netdev_ops = &nsim_netdev_ops; 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci err = nsim_udp_tunnels_info_create(ns->nsim_dev, ns->netdev); 33262306a36Sopenharmony_ci if (err) 33362306a36Sopenharmony_ci goto err_phc_destroy; 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci rtnl_lock(); 33662306a36Sopenharmony_ci err = nsim_bpf_init(ns); 33762306a36Sopenharmony_ci if (err) 33862306a36Sopenharmony_ci goto err_utn_destroy; 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci nsim_macsec_init(ns); 34162306a36Sopenharmony_ci nsim_ipsec_init(ns); 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci err = register_netdevice(ns->netdev); 34462306a36Sopenharmony_ci if (err) 34562306a36Sopenharmony_ci goto err_ipsec_teardown; 34662306a36Sopenharmony_ci rtnl_unlock(); 34762306a36Sopenharmony_ci return 0; 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_cierr_ipsec_teardown: 35062306a36Sopenharmony_ci nsim_ipsec_teardown(ns); 35162306a36Sopenharmony_ci nsim_macsec_teardown(ns); 35262306a36Sopenharmony_ci nsim_bpf_uninit(ns); 35362306a36Sopenharmony_cierr_utn_destroy: 35462306a36Sopenharmony_ci rtnl_unlock(); 35562306a36Sopenharmony_ci nsim_udp_tunnels_info_destroy(ns->netdev); 35662306a36Sopenharmony_cierr_phc_destroy: 35762306a36Sopenharmony_ci mock_phc_destroy(ns->phc); 35862306a36Sopenharmony_ci return err; 35962306a36Sopenharmony_ci} 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_cistatic int nsim_init_netdevsim_vf(struct netdevsim *ns) 36262306a36Sopenharmony_ci{ 36362306a36Sopenharmony_ci int err; 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci ns->netdev->netdev_ops = &nsim_vf_netdev_ops; 36662306a36Sopenharmony_ci rtnl_lock(); 36762306a36Sopenharmony_ci err = register_netdevice(ns->netdev); 36862306a36Sopenharmony_ci rtnl_unlock(); 36962306a36Sopenharmony_ci return err; 37062306a36Sopenharmony_ci} 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_cistatic void nsim_exit_netdevsim(struct netdevsim *ns) 37362306a36Sopenharmony_ci{ 37462306a36Sopenharmony_ci nsim_udp_tunnels_info_destroy(ns->netdev); 37562306a36Sopenharmony_ci mock_phc_destroy(ns->phc); 37662306a36Sopenharmony_ci} 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_cistruct netdevsim * 37962306a36Sopenharmony_cinsim_create(struct nsim_dev *nsim_dev, struct nsim_dev_port *nsim_dev_port) 38062306a36Sopenharmony_ci{ 38162306a36Sopenharmony_ci struct net_device *dev; 38262306a36Sopenharmony_ci struct netdevsim *ns; 38362306a36Sopenharmony_ci int err; 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci dev = alloc_netdev_mq(sizeof(*ns), "eth%d", NET_NAME_UNKNOWN, nsim_setup, 38662306a36Sopenharmony_ci nsim_dev->nsim_bus_dev->num_queues); 38762306a36Sopenharmony_ci if (!dev) 38862306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci dev_net_set(dev, nsim_dev_net(nsim_dev)); 39162306a36Sopenharmony_ci ns = netdev_priv(dev); 39262306a36Sopenharmony_ci ns->netdev = dev; 39362306a36Sopenharmony_ci u64_stats_init(&ns->syncp); 39462306a36Sopenharmony_ci ns->nsim_dev = nsim_dev; 39562306a36Sopenharmony_ci ns->nsim_dev_port = nsim_dev_port; 39662306a36Sopenharmony_ci ns->nsim_bus_dev = nsim_dev->nsim_bus_dev; 39762306a36Sopenharmony_ci SET_NETDEV_DEV(dev, &ns->nsim_bus_dev->dev); 39862306a36Sopenharmony_ci SET_NETDEV_DEVLINK_PORT(dev, &nsim_dev_port->devlink_port); 39962306a36Sopenharmony_ci nsim_ethtool_init(ns); 40062306a36Sopenharmony_ci if (nsim_dev_port_is_pf(nsim_dev_port)) 40162306a36Sopenharmony_ci err = nsim_init_netdevsim(ns); 40262306a36Sopenharmony_ci else 40362306a36Sopenharmony_ci err = nsim_init_netdevsim_vf(ns); 40462306a36Sopenharmony_ci if (err) 40562306a36Sopenharmony_ci goto err_free_netdev; 40662306a36Sopenharmony_ci return ns; 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_cierr_free_netdev: 40962306a36Sopenharmony_ci free_netdev(dev); 41062306a36Sopenharmony_ci return ERR_PTR(err); 41162306a36Sopenharmony_ci} 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_civoid nsim_destroy(struct netdevsim *ns) 41462306a36Sopenharmony_ci{ 41562306a36Sopenharmony_ci struct net_device *dev = ns->netdev; 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci rtnl_lock(); 41862306a36Sopenharmony_ci unregister_netdevice(dev); 41962306a36Sopenharmony_ci if (nsim_dev_port_is_pf(ns->nsim_dev_port)) { 42062306a36Sopenharmony_ci nsim_macsec_teardown(ns); 42162306a36Sopenharmony_ci nsim_ipsec_teardown(ns); 42262306a36Sopenharmony_ci nsim_bpf_uninit(ns); 42362306a36Sopenharmony_ci } 42462306a36Sopenharmony_ci rtnl_unlock(); 42562306a36Sopenharmony_ci if (nsim_dev_port_is_pf(ns->nsim_dev_port)) 42662306a36Sopenharmony_ci nsim_exit_netdevsim(ns); 42762306a36Sopenharmony_ci free_netdev(dev); 42862306a36Sopenharmony_ci} 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_cistatic int nsim_validate(struct nlattr *tb[], struct nlattr *data[], 43162306a36Sopenharmony_ci struct netlink_ext_ack *extack) 43262306a36Sopenharmony_ci{ 43362306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, 43462306a36Sopenharmony_ci "Please use: echo \"[ID] [PORT_COUNT] [NUM_QUEUES]\" > /sys/bus/netdevsim/new_device"); 43562306a36Sopenharmony_ci return -EOPNOTSUPP; 43662306a36Sopenharmony_ci} 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_cistatic struct rtnl_link_ops nsim_link_ops __read_mostly = { 43962306a36Sopenharmony_ci .kind = DRV_NAME, 44062306a36Sopenharmony_ci .validate = nsim_validate, 44162306a36Sopenharmony_ci}; 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_cistatic int __init nsim_module_init(void) 44462306a36Sopenharmony_ci{ 44562306a36Sopenharmony_ci int err; 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci err = nsim_dev_init(); 44862306a36Sopenharmony_ci if (err) 44962306a36Sopenharmony_ci return err; 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci err = nsim_bus_init(); 45262306a36Sopenharmony_ci if (err) 45362306a36Sopenharmony_ci goto err_dev_exit; 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci err = rtnl_link_register(&nsim_link_ops); 45662306a36Sopenharmony_ci if (err) 45762306a36Sopenharmony_ci goto err_bus_exit; 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci return 0; 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_cierr_bus_exit: 46262306a36Sopenharmony_ci nsim_bus_exit(); 46362306a36Sopenharmony_cierr_dev_exit: 46462306a36Sopenharmony_ci nsim_dev_exit(); 46562306a36Sopenharmony_ci return err; 46662306a36Sopenharmony_ci} 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_cistatic void __exit nsim_module_exit(void) 46962306a36Sopenharmony_ci{ 47062306a36Sopenharmony_ci rtnl_link_unregister(&nsim_link_ops); 47162306a36Sopenharmony_ci nsim_bus_exit(); 47262306a36Sopenharmony_ci nsim_dev_exit(); 47362306a36Sopenharmony_ci} 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_cimodule_init(nsim_module_init); 47662306a36Sopenharmony_cimodule_exit(nsim_module_exit); 47762306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 47862306a36Sopenharmony_ciMODULE_ALIAS_RTNL_LINK(DRV_NAME); 479