183c9e13aSJakub Kicinski /* 283c9e13aSJakub Kicinski * Copyright (C) 2017 Netronome Systems, Inc. 383c9e13aSJakub Kicinski * 483c9e13aSJakub Kicinski * This software is licensed under the GNU General License Version 2, 583c9e13aSJakub Kicinski * June 1991 as shown in the file COPYING in the top-level directory of this 683c9e13aSJakub Kicinski * source tree. 783c9e13aSJakub Kicinski * 883c9e13aSJakub Kicinski * THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" 983c9e13aSJakub Kicinski * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, 1083c9e13aSJakub Kicinski * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 1183c9e13aSJakub Kicinski * FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE 1283c9e13aSJakub Kicinski * OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME 1383c9e13aSJakub Kicinski * THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 1483c9e13aSJakub Kicinski */ 1583c9e13aSJakub Kicinski 1631d3ad83SJakub Kicinski #include <linux/debugfs.h> 1783c9e13aSJakub Kicinski #include <linux/etherdevice.h> 1883c9e13aSJakub Kicinski #include <linux/kernel.h> 1983c9e13aSJakub Kicinski #include <linux/module.h> 2083c9e13aSJakub Kicinski #include <linux/netdevice.h> 2183c9e13aSJakub Kicinski #include <linux/slab.h> 22f216306bSJakub Kicinski #include <net/netdev_queues.h> 231580cbcbSJakub Kicinski #include <net/page_pool/helpers.h> 2483c9e13aSJakub Kicinski #include <net/netlink.h> 25b3ea4164SPaolo Abeni #include <net/net_shaper.h> 2631d3ad83SJakub Kicinski #include <net/pkt_cls.h> 2783c9e13aSJakub Kicinski #include <net/rtnetlink.h> 28424be63aSJakub Kicinski #include <net/udp_tunnel.h> 2983c9e13aSJakub Kicinski 3083c9e13aSJakub Kicinski #include "netdevsim.h" 3183c9e13aSJakub Kicinski 323762ec05SDavid Wei #define NSIM_RING_SIZE 256 333762ec05SDavid Wei 343762ec05SDavid Wei static int nsim_napi_rx(struct nsim_rq *rq, struct sk_buff *skb) 353762ec05SDavid Wei { 363762ec05SDavid Wei if (skb_queue_len(&rq->skb_queue) > NSIM_RING_SIZE) { 373762ec05SDavid Wei dev_kfree_skb_any(skb); 383762ec05SDavid Wei return NET_RX_DROP; 393762ec05SDavid Wei } 403762ec05SDavid Wei 413762ec05SDavid Wei skb_queue_tail(&rq->skb_queue, skb); 423762ec05SDavid Wei return NET_RX_SUCCESS; 433762ec05SDavid Wei } 443762ec05SDavid Wei 453762ec05SDavid Wei static int nsim_forward_skb(struct net_device *dev, struct sk_buff *skb, 463762ec05SDavid Wei struct nsim_rq *rq) 473762ec05SDavid Wei { 483762ec05SDavid Wei return __dev_forward_skb(dev, skb) ?: nsim_napi_rx(rq, skb); 493762ec05SDavid Wei } 503762ec05SDavid Wei 5183c9e13aSJakub Kicinski static netdev_tx_t nsim_start_xmit(struct sk_buff *skb, struct net_device *dev) 5283c9e13aSJakub Kicinski { 5383c9e13aSJakub Kicinski struct netdevsim *ns = netdev_priv(dev); 543762ec05SDavid Wei struct net_device *peer_dev; 559eb95228SDavid Wei unsigned int len = skb->len; 569eb95228SDavid Wei struct netdevsim *peer_ns; 573762ec05SDavid Wei struct nsim_rq *rq; 583762ec05SDavid Wei int rxq; 5983c9e13aSJakub Kicinski 609eb95228SDavid Wei rcu_read_lock(); 617699353dSShannon Nelson if (!nsim_ipsec_tx(ns, skb)) 629eb95228SDavid Wei goto out_drop_free; 637699353dSShannon Nelson 649eb95228SDavid Wei peer_ns = rcu_dereference(ns->peer); 659eb95228SDavid Wei if (!peer_ns) 669eb95228SDavid Wei goto out_drop_free; 679eb95228SDavid Wei 683762ec05SDavid Wei peer_dev = peer_ns->netdev; 693762ec05SDavid Wei rxq = skb_get_queue_mapping(skb); 703762ec05SDavid Wei if (rxq >= peer_dev->num_rx_queues) 713762ec05SDavid Wei rxq = rxq % peer_dev->num_rx_queues; 723762ec05SDavid Wei rq = &peer_ns->rq[rxq]; 733762ec05SDavid Wei 749eb95228SDavid Wei skb_tx_timestamp(skb); 753762ec05SDavid Wei if (unlikely(nsim_forward_skb(peer_dev, skb, rq) == NET_RX_DROP)) 769eb95228SDavid Wei goto out_drop_cnt; 779eb95228SDavid Wei 783762ec05SDavid Wei napi_schedule(&rq->napi); 793762ec05SDavid Wei 809eb95228SDavid Wei rcu_read_unlock(); 8183c9e13aSJakub Kicinski u64_stats_update_begin(&ns->syncp); 8283c9e13aSJakub Kicinski ns->tx_packets++; 839eb95228SDavid Wei ns->tx_bytes += len; 8483c9e13aSJakub Kicinski u64_stats_update_end(&ns->syncp); 859eb95228SDavid Wei return NETDEV_TX_OK; 8683c9e13aSJakub Kicinski 879eb95228SDavid Wei out_drop_free: 8883c9e13aSJakub Kicinski dev_kfree_skb(skb); 899eb95228SDavid Wei out_drop_cnt: 909eb95228SDavid Wei rcu_read_unlock(); 919eb95228SDavid Wei u64_stats_update_begin(&ns->syncp); 929eb95228SDavid Wei ns->tx_dropped++; 939eb95228SDavid Wei u64_stats_update_end(&ns->syncp); 9483c9e13aSJakub Kicinski return NETDEV_TX_OK; 9583c9e13aSJakub Kicinski } 9683c9e13aSJakub Kicinski 9783c9e13aSJakub Kicinski static void nsim_set_rx_mode(struct net_device *dev) 9883c9e13aSJakub Kicinski { 9983c9e13aSJakub Kicinski } 10083c9e13aSJakub Kicinski 10131d3ad83SJakub Kicinski static int nsim_change_mtu(struct net_device *dev, int new_mtu) 10231d3ad83SJakub Kicinski { 10331d3ad83SJakub Kicinski struct netdevsim *ns = netdev_priv(dev); 10431d3ad83SJakub Kicinski 105799e173dSJakub Kicinski if (ns->xdp.prog && new_mtu > NSIM_XDP_MAX_MTU) 10631d3ad83SJakub Kicinski return -EBUSY; 10731d3ad83SJakub Kicinski 1081eb2cdedSEric Dumazet WRITE_ONCE(dev->mtu, new_mtu); 10931d3ad83SJakub Kicinski 11031d3ad83SJakub Kicinski return 0; 11131d3ad83SJakub Kicinski } 11231d3ad83SJakub Kicinski 11383c9e13aSJakub Kicinski static void 11483c9e13aSJakub Kicinski nsim_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) 11583c9e13aSJakub Kicinski { 11683c9e13aSJakub Kicinski struct netdevsim *ns = netdev_priv(dev); 11783c9e13aSJakub Kicinski unsigned int start; 11883c9e13aSJakub Kicinski 11983c9e13aSJakub Kicinski do { 120068c38adSThomas Gleixner start = u64_stats_fetch_begin(&ns->syncp); 12183c9e13aSJakub Kicinski stats->tx_bytes = ns->tx_bytes; 12283c9e13aSJakub Kicinski stats->tx_packets = ns->tx_packets; 1239eb95228SDavid Wei stats->tx_dropped = ns->tx_dropped; 124068c38adSThomas Gleixner } while (u64_stats_fetch_retry(&ns->syncp, start)); 12583c9e13aSJakub Kicinski } 12683c9e13aSJakub Kicinski 12731d3ad83SJakub Kicinski static int 12831d3ad83SJakub Kicinski nsim_setup_tc_block_cb(enum tc_setup_type type, void *type_data, void *cb_priv) 12931d3ad83SJakub Kicinski { 13031d3ad83SJakub Kicinski return nsim_bpf_setup_tc_block_cb(type, type_data, cb_priv); 13131d3ad83SJakub Kicinski } 13231d3ad83SJakub Kicinski 13379579220SJakub Kicinski static int nsim_set_vf_mac(struct net_device *dev, int vf, u8 *mac) 13479579220SJakub Kicinski { 13579579220SJakub Kicinski struct netdevsim *ns = netdev_priv(dev); 1365e388f3dSJakub Kicinski struct nsim_dev *nsim_dev = ns->nsim_dev; 13779579220SJakub Kicinski 13879579220SJakub Kicinski /* Only refuse multicast addresses, zero address can mean unset/any. */ 1395e388f3dSJakub Kicinski if (vf >= nsim_dev_get_vfs(nsim_dev) || is_multicast_ether_addr(mac)) 14079579220SJakub Kicinski return -EINVAL; 1415e388f3dSJakub Kicinski memcpy(nsim_dev->vfconfigs[vf].vf_mac, mac, ETH_ALEN); 14279579220SJakub Kicinski 14379579220SJakub Kicinski return 0; 14479579220SJakub Kicinski } 14579579220SJakub Kicinski 14679579220SJakub Kicinski static int nsim_set_vf_vlan(struct net_device *dev, int vf, 14779579220SJakub Kicinski u16 vlan, u8 qos, __be16 vlan_proto) 14879579220SJakub Kicinski { 14979579220SJakub Kicinski struct netdevsim *ns = netdev_priv(dev); 1505e388f3dSJakub Kicinski struct nsim_dev *nsim_dev = ns->nsim_dev; 15179579220SJakub Kicinski 1525e388f3dSJakub Kicinski if (vf >= nsim_dev_get_vfs(nsim_dev) || vlan > 4095 || qos > 7) 15379579220SJakub Kicinski return -EINVAL; 15479579220SJakub Kicinski 1555e388f3dSJakub Kicinski nsim_dev->vfconfigs[vf].vlan = vlan; 1565e388f3dSJakub Kicinski nsim_dev->vfconfigs[vf].qos = qos; 1575e388f3dSJakub Kicinski nsim_dev->vfconfigs[vf].vlan_proto = vlan_proto; 15879579220SJakub Kicinski 15979579220SJakub Kicinski return 0; 16079579220SJakub Kicinski } 16179579220SJakub Kicinski 16279579220SJakub Kicinski static int nsim_set_vf_rate(struct net_device *dev, int vf, int min, int max) 16379579220SJakub Kicinski { 16479579220SJakub Kicinski struct netdevsim *ns = netdev_priv(dev); 1655e388f3dSJakub Kicinski struct nsim_dev *nsim_dev = ns->nsim_dev; 16679579220SJakub Kicinski 167160dc373SDmytro Linkin if (nsim_esw_mode_is_switchdev(ns->nsim_dev)) { 168160dc373SDmytro Linkin pr_err("Not supported in switchdev mode. Please use devlink API.\n"); 169160dc373SDmytro Linkin return -EOPNOTSUPP; 170160dc373SDmytro Linkin } 171160dc373SDmytro Linkin 1725e388f3dSJakub Kicinski if (vf >= nsim_dev_get_vfs(nsim_dev)) 17379579220SJakub Kicinski return -EINVAL; 17479579220SJakub Kicinski 1755e388f3dSJakub Kicinski nsim_dev->vfconfigs[vf].min_tx_rate = min; 1765e388f3dSJakub Kicinski nsim_dev->vfconfigs[vf].max_tx_rate = max; 17779579220SJakub Kicinski 17879579220SJakub Kicinski return 0; 17979579220SJakub Kicinski } 18079579220SJakub Kicinski 18179579220SJakub Kicinski static int nsim_set_vf_spoofchk(struct net_device *dev, int vf, bool val) 18279579220SJakub Kicinski { 18379579220SJakub Kicinski struct netdevsim *ns = netdev_priv(dev); 1845e388f3dSJakub Kicinski struct nsim_dev *nsim_dev = ns->nsim_dev; 18579579220SJakub Kicinski 1865e388f3dSJakub Kicinski if (vf >= nsim_dev_get_vfs(nsim_dev)) 18779579220SJakub Kicinski return -EINVAL; 1885e388f3dSJakub Kicinski nsim_dev->vfconfigs[vf].spoofchk_enabled = val; 18979579220SJakub Kicinski 19079579220SJakub Kicinski return 0; 19179579220SJakub Kicinski } 19279579220SJakub Kicinski 19379579220SJakub Kicinski static int nsim_set_vf_rss_query_en(struct net_device *dev, int vf, bool val) 19479579220SJakub Kicinski { 19579579220SJakub Kicinski struct netdevsim *ns = netdev_priv(dev); 1965e388f3dSJakub Kicinski struct nsim_dev *nsim_dev = ns->nsim_dev; 19779579220SJakub Kicinski 1985e388f3dSJakub Kicinski if (vf >= nsim_dev_get_vfs(nsim_dev)) 19979579220SJakub Kicinski return -EINVAL; 2005e388f3dSJakub Kicinski nsim_dev->vfconfigs[vf].rss_query_enabled = val; 20179579220SJakub Kicinski 20279579220SJakub Kicinski return 0; 20379579220SJakub Kicinski } 20479579220SJakub Kicinski 20579579220SJakub Kicinski static int nsim_set_vf_trust(struct net_device *dev, int vf, bool val) 20679579220SJakub Kicinski { 20779579220SJakub Kicinski struct netdevsim *ns = netdev_priv(dev); 2085e388f3dSJakub Kicinski struct nsim_dev *nsim_dev = ns->nsim_dev; 20979579220SJakub Kicinski 2105e388f3dSJakub Kicinski if (vf >= nsim_dev_get_vfs(nsim_dev)) 21179579220SJakub Kicinski return -EINVAL; 2125e388f3dSJakub Kicinski nsim_dev->vfconfigs[vf].trusted = val; 21379579220SJakub Kicinski 21479579220SJakub Kicinski return 0; 21579579220SJakub Kicinski } 21679579220SJakub Kicinski 21779579220SJakub Kicinski static int 21879579220SJakub Kicinski nsim_get_vf_config(struct net_device *dev, int vf, struct ifla_vf_info *ivi) 21979579220SJakub Kicinski { 22079579220SJakub Kicinski struct netdevsim *ns = netdev_priv(dev); 2215e388f3dSJakub Kicinski struct nsim_dev *nsim_dev = ns->nsim_dev; 22279579220SJakub Kicinski 2235e388f3dSJakub Kicinski if (vf >= nsim_dev_get_vfs(nsim_dev)) 22479579220SJakub Kicinski return -EINVAL; 22579579220SJakub Kicinski 22679579220SJakub Kicinski ivi->vf = vf; 2275e388f3dSJakub Kicinski ivi->linkstate = nsim_dev->vfconfigs[vf].link_state; 2285e388f3dSJakub Kicinski ivi->min_tx_rate = nsim_dev->vfconfigs[vf].min_tx_rate; 2295e388f3dSJakub Kicinski ivi->max_tx_rate = nsim_dev->vfconfigs[vf].max_tx_rate; 2305e388f3dSJakub Kicinski ivi->vlan = nsim_dev->vfconfigs[vf].vlan; 2315e388f3dSJakub Kicinski ivi->vlan_proto = nsim_dev->vfconfigs[vf].vlan_proto; 2325e388f3dSJakub Kicinski ivi->qos = nsim_dev->vfconfigs[vf].qos; 2335e388f3dSJakub Kicinski memcpy(&ivi->mac, nsim_dev->vfconfigs[vf].vf_mac, ETH_ALEN); 2345e388f3dSJakub Kicinski ivi->spoofchk = nsim_dev->vfconfigs[vf].spoofchk_enabled; 2355e388f3dSJakub Kicinski ivi->trusted = nsim_dev->vfconfigs[vf].trusted; 2365e388f3dSJakub Kicinski ivi->rss_query_en = nsim_dev->vfconfigs[vf].rss_query_enabled; 23779579220SJakub Kicinski 23879579220SJakub Kicinski return 0; 23979579220SJakub Kicinski } 24079579220SJakub Kicinski 24179579220SJakub Kicinski static int nsim_set_vf_link_state(struct net_device *dev, int vf, int state) 24279579220SJakub Kicinski { 24379579220SJakub Kicinski struct netdevsim *ns = netdev_priv(dev); 2445e388f3dSJakub Kicinski struct nsim_dev *nsim_dev = ns->nsim_dev; 24579579220SJakub Kicinski 2465e388f3dSJakub Kicinski if (vf >= nsim_dev_get_vfs(nsim_dev)) 24779579220SJakub Kicinski return -EINVAL; 24879579220SJakub Kicinski 24979579220SJakub Kicinski switch (state) { 25079579220SJakub Kicinski case IFLA_VF_LINK_STATE_AUTO: 25179579220SJakub Kicinski case IFLA_VF_LINK_STATE_ENABLE: 25279579220SJakub Kicinski case IFLA_VF_LINK_STATE_DISABLE: 25379579220SJakub Kicinski break; 25479579220SJakub Kicinski default: 25579579220SJakub Kicinski return -EINVAL; 25679579220SJakub Kicinski } 25779579220SJakub Kicinski 2585e388f3dSJakub Kicinski nsim_dev->vfconfigs[vf].link_state = state; 25979579220SJakub Kicinski 26079579220SJakub Kicinski return 0; 26179579220SJakub Kicinski } 26279579220SJakub Kicinski 26335da47feSVladimir Oltean static void nsim_taprio_stats(struct tc_taprio_qopt_stats *stats) 26435da47feSVladimir Oltean { 26535da47feSVladimir Oltean stats->window_drops = 0; 26635da47feSVladimir Oltean stats->tx_overruns = 0; 26735da47feSVladimir Oltean } 26835da47feSVladimir Oltean 26935da47feSVladimir Oltean static int nsim_setup_tc_taprio(struct net_device *dev, 27035da47feSVladimir Oltean struct tc_taprio_qopt_offload *offload) 27135da47feSVladimir Oltean { 27235da47feSVladimir Oltean int err = 0; 27335da47feSVladimir Oltean 27435da47feSVladimir Oltean switch (offload->cmd) { 27535da47feSVladimir Oltean case TAPRIO_CMD_REPLACE: 27635da47feSVladimir Oltean case TAPRIO_CMD_DESTROY: 27735da47feSVladimir Oltean break; 27835da47feSVladimir Oltean case TAPRIO_CMD_STATS: 27935da47feSVladimir Oltean nsim_taprio_stats(&offload->stats); 28035da47feSVladimir Oltean break; 28135da47feSVladimir Oltean default: 28235da47feSVladimir Oltean err = -EOPNOTSUPP; 28335da47feSVladimir Oltean } 28435da47feSVladimir Oltean 28535da47feSVladimir Oltean return err; 28635da47feSVladimir Oltean } 28735da47feSVladimir Oltean 288955bcb6eSPablo Neira Ayuso static LIST_HEAD(nsim_block_cb_list); 289955bcb6eSPablo Neira Ayuso 29031d3ad83SJakub Kicinski static int 29131d3ad83SJakub Kicinski nsim_setup_tc(struct net_device *dev, enum tc_setup_type type, void *type_data) 29231d3ad83SJakub Kicinski { 2934e95bc26SPablo Neira Ayuso struct netdevsim *ns = netdev_priv(dev); 2944e95bc26SPablo Neira Ayuso 29531d3ad83SJakub Kicinski switch (type) { 29635da47feSVladimir Oltean case TC_SETUP_QDISC_TAPRIO: 29735da47feSVladimir Oltean return nsim_setup_tc_taprio(dev, type_data); 29831d3ad83SJakub Kicinski case TC_SETUP_BLOCK: 299955bcb6eSPablo Neira Ayuso return flow_block_cb_setup_simple(type_data, 300955bcb6eSPablo Neira Ayuso &nsim_block_cb_list, 3014e95bc26SPablo Neira Ayuso nsim_setup_tc_block_cb, 3024e95bc26SPablo Neira Ayuso ns, ns, true); 30331d3ad83SJakub Kicinski default: 30431d3ad83SJakub Kicinski return -EOPNOTSUPP; 30531d3ad83SJakub Kicinski } 30631d3ad83SJakub Kicinski } 30731d3ad83SJakub Kicinski 30831d3ad83SJakub Kicinski static int 30931d3ad83SJakub Kicinski nsim_set_features(struct net_device *dev, netdev_features_t features) 31031d3ad83SJakub Kicinski { 31131d3ad83SJakub Kicinski struct netdevsim *ns = netdev_priv(dev); 31231d3ad83SJakub Kicinski 31331d3ad83SJakub Kicinski if ((dev->features & NETIF_F_HW_TC) > (features & NETIF_F_HW_TC)) 31431d3ad83SJakub Kicinski return nsim_bpf_disable_tc(ns); 31531d3ad83SJakub Kicinski 31631d3ad83SJakub Kicinski return 0; 31731d3ad83SJakub Kicinski } 31831d3ad83SJakub Kicinski 3198debcf58SDavid Wei static int nsim_get_iflink(const struct net_device *dev) 3208debcf58SDavid Wei { 3218debcf58SDavid Wei struct netdevsim *nsim, *peer; 3228debcf58SDavid Wei int iflink; 3238debcf58SDavid Wei 3248debcf58SDavid Wei nsim = netdev_priv(dev); 3258debcf58SDavid Wei 3268debcf58SDavid Wei rcu_read_lock(); 3278debcf58SDavid Wei peer = rcu_dereference(nsim->peer); 3285add2f72SDavid Wei iflink = peer ? READ_ONCE(peer->netdev->ifindex) : 3295add2f72SDavid Wei READ_ONCE(dev->ifindex); 3308debcf58SDavid Wei rcu_read_unlock(); 3318debcf58SDavid Wei 3328debcf58SDavid Wei return iflink; 3338debcf58SDavid Wei } 3348debcf58SDavid Wei 3353762ec05SDavid Wei static int nsim_rcv(struct nsim_rq *rq, int budget) 3363762ec05SDavid Wei { 3373762ec05SDavid Wei struct sk_buff *skb; 3383762ec05SDavid Wei int i; 3393762ec05SDavid Wei 3403762ec05SDavid Wei for (i = 0; i < budget; i++) { 3413762ec05SDavid Wei if (skb_queue_empty(&rq->skb_queue)) 3423762ec05SDavid Wei break; 3433762ec05SDavid Wei 3443762ec05SDavid Wei skb = skb_dequeue(&rq->skb_queue); 3453762ec05SDavid Wei netif_receive_skb(skb); 3463762ec05SDavid Wei } 3473762ec05SDavid Wei 3483762ec05SDavid Wei return i; 3493762ec05SDavid Wei } 3503762ec05SDavid Wei 3513762ec05SDavid Wei static int nsim_poll(struct napi_struct *napi, int budget) 3523762ec05SDavid Wei { 3533762ec05SDavid Wei struct nsim_rq *rq = container_of(napi, struct nsim_rq, napi); 3543762ec05SDavid Wei int done; 3553762ec05SDavid Wei 3563762ec05SDavid Wei done = nsim_rcv(rq, budget); 3573762ec05SDavid Wei napi_complete(napi); 3583762ec05SDavid Wei 3593762ec05SDavid Wei return done; 3603762ec05SDavid Wei } 3613762ec05SDavid Wei 3623762ec05SDavid Wei static int nsim_create_page_pool(struct nsim_rq *rq) 3633762ec05SDavid Wei { 3643762ec05SDavid Wei struct page_pool_params p = { 3653762ec05SDavid Wei .order = 0, 3663762ec05SDavid Wei .pool_size = NSIM_RING_SIZE, 3673762ec05SDavid Wei .nid = NUMA_NO_NODE, 3683762ec05SDavid Wei .dev = &rq->napi.dev->dev, 3693762ec05SDavid Wei .napi = &rq->napi, 3703762ec05SDavid Wei .dma_dir = DMA_BIDIRECTIONAL, 3713762ec05SDavid Wei .netdev = rq->napi.dev, 3723762ec05SDavid Wei }; 3733762ec05SDavid Wei 3743762ec05SDavid Wei rq->page_pool = page_pool_create(&p); 3753762ec05SDavid Wei if (IS_ERR(rq->page_pool)) { 3763762ec05SDavid Wei int err = PTR_ERR(rq->page_pool); 3773762ec05SDavid Wei 3783762ec05SDavid Wei rq->page_pool = NULL; 3793762ec05SDavid Wei return err; 3803762ec05SDavid Wei } 3813762ec05SDavid Wei return 0; 3823762ec05SDavid Wei } 3833762ec05SDavid Wei 3843762ec05SDavid Wei static int nsim_init_napi(struct netdevsim *ns) 3853762ec05SDavid Wei { 3863762ec05SDavid Wei struct net_device *dev = ns->netdev; 3873762ec05SDavid Wei struct nsim_rq *rq; 3883762ec05SDavid Wei int err, i; 3893762ec05SDavid Wei 3903762ec05SDavid Wei for (i = 0; i < dev->num_rx_queues; i++) { 3913762ec05SDavid Wei rq = &ns->rq[i]; 3923762ec05SDavid Wei 393*00adf88bSJakub Kicinski netif_napi_add_config(dev, &rq->napi, nsim_poll, i); 3943762ec05SDavid Wei } 3953762ec05SDavid Wei 3963762ec05SDavid Wei for (i = 0; i < dev->num_rx_queues; i++) { 3973762ec05SDavid Wei rq = &ns->rq[i]; 3983762ec05SDavid Wei 3993762ec05SDavid Wei err = nsim_create_page_pool(rq); 4003762ec05SDavid Wei if (err) 4013762ec05SDavid Wei goto err_pp_destroy; 4023762ec05SDavid Wei } 4033762ec05SDavid Wei 4043762ec05SDavid Wei return 0; 4053762ec05SDavid Wei 4063762ec05SDavid Wei err_pp_destroy: 4073762ec05SDavid Wei while (i--) { 4083762ec05SDavid Wei page_pool_destroy(ns->rq[i].page_pool); 4093762ec05SDavid Wei ns->rq[i].page_pool = NULL; 4103762ec05SDavid Wei } 4113762ec05SDavid Wei 4123762ec05SDavid Wei for (i = 0; i < dev->num_rx_queues; i++) 4133762ec05SDavid Wei __netif_napi_del(&ns->rq[i].napi); 4143762ec05SDavid Wei 4153762ec05SDavid Wei return err; 4163762ec05SDavid Wei } 4173762ec05SDavid Wei 4183762ec05SDavid Wei static void nsim_enable_napi(struct netdevsim *ns) 4193762ec05SDavid Wei { 4203762ec05SDavid Wei struct net_device *dev = ns->netdev; 4213762ec05SDavid Wei int i; 4223762ec05SDavid Wei 4233762ec05SDavid Wei for (i = 0; i < dev->num_rx_queues; i++) { 4243762ec05SDavid Wei struct nsim_rq *rq = &ns->rq[i]; 4253762ec05SDavid Wei 4263762ec05SDavid Wei netif_queue_set_napi(dev, i, NETDEV_QUEUE_TYPE_RX, &rq->napi); 4273762ec05SDavid Wei napi_enable(&rq->napi); 4283762ec05SDavid Wei } 4293762ec05SDavid Wei } 4303762ec05SDavid Wei 4311580cbcbSJakub Kicinski static int nsim_open(struct net_device *dev) 4321580cbcbSJakub Kicinski { 4331580cbcbSJakub Kicinski struct netdevsim *ns = netdev_priv(dev); 4343762ec05SDavid Wei int err; 4351580cbcbSJakub Kicinski 4363762ec05SDavid Wei err = nsim_init_napi(ns); 4373762ec05SDavid Wei if (err) 4383762ec05SDavid Wei return err; 4391580cbcbSJakub Kicinski 4403762ec05SDavid Wei nsim_enable_napi(ns); 4413762ec05SDavid Wei 4423762ec05SDavid Wei return 0; 4433762ec05SDavid Wei } 4443762ec05SDavid Wei 4453762ec05SDavid Wei static void nsim_del_napi(struct netdevsim *ns) 4463762ec05SDavid Wei { 4473762ec05SDavid Wei struct net_device *dev = ns->netdev; 4483762ec05SDavid Wei int i; 4493762ec05SDavid Wei 4503762ec05SDavid Wei for (i = 0; i < dev->num_rx_queues; i++) { 4513762ec05SDavid Wei struct nsim_rq *rq = &ns->rq[i]; 4523762ec05SDavid Wei 4533762ec05SDavid Wei napi_disable(&rq->napi); 4543762ec05SDavid Wei __netif_napi_del(&rq->napi); 4553762ec05SDavid Wei } 4563762ec05SDavid Wei synchronize_net(); 4573762ec05SDavid Wei 4583762ec05SDavid Wei for (i = 0; i < dev->num_rx_queues; i++) { 4593762ec05SDavid Wei page_pool_destroy(ns->rq[i].page_pool); 4603762ec05SDavid Wei ns->rq[i].page_pool = NULL; 4613762ec05SDavid Wei } 4621580cbcbSJakub Kicinski } 4631580cbcbSJakub Kicinski 4641580cbcbSJakub Kicinski static int nsim_stop(struct net_device *dev) 4651580cbcbSJakub Kicinski { 4661580cbcbSJakub Kicinski struct netdevsim *ns = netdev_priv(dev); 4673762ec05SDavid Wei struct netdevsim *peer; 4681580cbcbSJakub Kicinski 4693762ec05SDavid Wei netif_carrier_off(dev); 4703762ec05SDavid Wei peer = rtnl_dereference(ns->peer); 4713762ec05SDavid Wei if (peer) 4723762ec05SDavid Wei netif_carrier_off(peer->netdev); 4733762ec05SDavid Wei 4743762ec05SDavid Wei nsim_del_napi(ns); 4751580cbcbSJakub Kicinski 4761580cbcbSJakub Kicinski return 0; 4771580cbcbSJakub Kicinski } 4781580cbcbSJakub Kicinski 479b3ea4164SPaolo Abeni static int nsim_shaper_set(struct net_shaper_binding *binding, 480b3ea4164SPaolo Abeni const struct net_shaper *shaper, 481b3ea4164SPaolo Abeni struct netlink_ext_ack *extack) 482b3ea4164SPaolo Abeni { 483b3ea4164SPaolo Abeni return 0; 484b3ea4164SPaolo Abeni } 485b3ea4164SPaolo Abeni 486b3ea4164SPaolo Abeni static int nsim_shaper_del(struct net_shaper_binding *binding, 487b3ea4164SPaolo Abeni const struct net_shaper_handle *handle, 488b3ea4164SPaolo Abeni struct netlink_ext_ack *extack) 489b3ea4164SPaolo Abeni { 490b3ea4164SPaolo Abeni return 0; 491b3ea4164SPaolo Abeni } 492b3ea4164SPaolo Abeni 493b3ea4164SPaolo Abeni static int nsim_shaper_group(struct net_shaper_binding *binding, 494b3ea4164SPaolo Abeni int leaves_count, 495b3ea4164SPaolo Abeni const struct net_shaper *leaves, 496b3ea4164SPaolo Abeni const struct net_shaper *root, 497b3ea4164SPaolo Abeni struct netlink_ext_ack *extack) 498b3ea4164SPaolo Abeni { 499b3ea4164SPaolo Abeni return 0; 500b3ea4164SPaolo Abeni } 501b3ea4164SPaolo Abeni 502b3ea4164SPaolo Abeni static void nsim_shaper_cap(struct net_shaper_binding *binding, 503b3ea4164SPaolo Abeni enum net_shaper_scope scope, 504b3ea4164SPaolo Abeni unsigned long *flags) 505b3ea4164SPaolo Abeni { 506b3ea4164SPaolo Abeni *flags = ULONG_MAX; 507b3ea4164SPaolo Abeni } 508b3ea4164SPaolo Abeni 509b3ea4164SPaolo Abeni static const struct net_shaper_ops nsim_shaper_ops = { 510b3ea4164SPaolo Abeni .set = nsim_shaper_set, 511b3ea4164SPaolo Abeni .delete = nsim_shaper_del, 512b3ea4164SPaolo Abeni .group = nsim_shaper_group, 513b3ea4164SPaolo Abeni .capabilities = nsim_shaper_cap, 514b3ea4164SPaolo Abeni }; 515b3ea4164SPaolo Abeni 51683c9e13aSJakub Kicinski static const struct net_device_ops nsim_netdev_ops = { 51783c9e13aSJakub Kicinski .ndo_start_xmit = nsim_start_xmit, 51883c9e13aSJakub Kicinski .ndo_set_rx_mode = nsim_set_rx_mode, 51983c9e13aSJakub Kicinski .ndo_set_mac_address = eth_mac_addr, 52083c9e13aSJakub Kicinski .ndo_validate_addr = eth_validate_addr, 52131d3ad83SJakub Kicinski .ndo_change_mtu = nsim_change_mtu, 52283c9e13aSJakub Kicinski .ndo_get_stats64 = nsim_get_stats64, 52379579220SJakub Kicinski .ndo_set_vf_mac = nsim_set_vf_mac, 52479579220SJakub Kicinski .ndo_set_vf_vlan = nsim_set_vf_vlan, 52579579220SJakub Kicinski .ndo_set_vf_rate = nsim_set_vf_rate, 52679579220SJakub Kicinski .ndo_set_vf_spoofchk = nsim_set_vf_spoofchk, 52779579220SJakub Kicinski .ndo_set_vf_trust = nsim_set_vf_trust, 52879579220SJakub Kicinski .ndo_get_vf_config = nsim_get_vf_config, 52979579220SJakub Kicinski .ndo_set_vf_link_state = nsim_set_vf_link_state, 53079579220SJakub Kicinski .ndo_set_vf_rss_query_en = nsim_set_vf_rss_query_en, 53131d3ad83SJakub Kicinski .ndo_setup_tc = nsim_setup_tc, 53231d3ad83SJakub Kicinski .ndo_set_features = nsim_set_features, 5338debcf58SDavid Wei .ndo_get_iflink = nsim_get_iflink, 53431d3ad83SJakub Kicinski .ndo_bpf = nsim_bpf, 5351580cbcbSJakub Kicinski .ndo_open = nsim_open, 5361580cbcbSJakub Kicinski .ndo_stop = nsim_stop, 537b3ea4164SPaolo Abeni .net_shaper_ops = &nsim_shaper_ops, 53883c9e13aSJakub Kicinski }; 53983c9e13aSJakub Kicinski 54092ba1f29SDmytro Linkin static const struct net_device_ops nsim_vf_netdev_ops = { 54192ba1f29SDmytro Linkin .ndo_start_xmit = nsim_start_xmit, 54292ba1f29SDmytro Linkin .ndo_set_rx_mode = nsim_set_rx_mode, 54392ba1f29SDmytro Linkin .ndo_set_mac_address = eth_mac_addr, 54492ba1f29SDmytro Linkin .ndo_validate_addr = eth_validate_addr, 54592ba1f29SDmytro Linkin .ndo_change_mtu = nsim_change_mtu, 54692ba1f29SDmytro Linkin .ndo_get_stats64 = nsim_get_stats64, 54792ba1f29SDmytro Linkin .ndo_setup_tc = nsim_setup_tc, 54892ba1f29SDmytro Linkin .ndo_set_features = nsim_set_features, 54992ba1f29SDmytro Linkin }; 55092ba1f29SDmytro Linkin 551f216306bSJakub Kicinski /* We don't have true per-queue stats, yet, so do some random fakery here. 552f216306bSJakub Kicinski * Only report stuff for queue 0. 553f216306bSJakub Kicinski */ 554f216306bSJakub Kicinski static void nsim_get_queue_stats_rx(struct net_device *dev, int idx, 555f216306bSJakub Kicinski struct netdev_queue_stats_rx *stats) 556f216306bSJakub Kicinski { 557f216306bSJakub Kicinski struct rtnl_link_stats64 rtstats = {}; 558f216306bSJakub Kicinski 559f216306bSJakub Kicinski if (!idx) 560f216306bSJakub Kicinski nsim_get_stats64(dev, &rtstats); 561f216306bSJakub Kicinski 562f216306bSJakub Kicinski stats->packets = rtstats.rx_packets - !!rtstats.rx_packets; 563f216306bSJakub Kicinski stats->bytes = rtstats.rx_bytes; 564f216306bSJakub Kicinski } 565f216306bSJakub Kicinski 566f216306bSJakub Kicinski static void nsim_get_queue_stats_tx(struct net_device *dev, int idx, 567f216306bSJakub Kicinski struct netdev_queue_stats_tx *stats) 568f216306bSJakub Kicinski { 569f216306bSJakub Kicinski struct rtnl_link_stats64 rtstats = {}; 570f216306bSJakub Kicinski 571f216306bSJakub Kicinski if (!idx) 572f216306bSJakub Kicinski nsim_get_stats64(dev, &rtstats); 573f216306bSJakub Kicinski 574f216306bSJakub Kicinski stats->packets = rtstats.tx_packets - !!rtstats.tx_packets; 575f216306bSJakub Kicinski stats->bytes = rtstats.tx_bytes; 576f216306bSJakub Kicinski } 577f216306bSJakub Kicinski 578f216306bSJakub Kicinski static void nsim_get_base_stats(struct net_device *dev, 579f216306bSJakub Kicinski struct netdev_queue_stats_rx *rx, 580f216306bSJakub Kicinski struct netdev_queue_stats_tx *tx) 581f216306bSJakub Kicinski { 582f216306bSJakub Kicinski struct rtnl_link_stats64 rtstats = {}; 583f216306bSJakub Kicinski 584f216306bSJakub Kicinski nsim_get_stats64(dev, &rtstats); 585f216306bSJakub Kicinski 586f216306bSJakub Kicinski rx->packets = !!rtstats.rx_packets; 587f216306bSJakub Kicinski rx->bytes = 0; 588f216306bSJakub Kicinski tx->packets = !!rtstats.tx_packets; 589f216306bSJakub Kicinski tx->bytes = 0; 590f216306bSJakub Kicinski } 591f216306bSJakub Kicinski 592f216306bSJakub Kicinski static const struct netdev_stat_ops nsim_stat_ops = { 593f216306bSJakub Kicinski .get_queue_stats_tx = nsim_get_queue_stats_tx, 594f216306bSJakub Kicinski .get_queue_stats_rx = nsim_get_queue_stats_rx, 595f216306bSJakub Kicinski .get_base_stats = nsim_get_base_stats, 596f216306bSJakub Kicinski }; 597f216306bSJakub Kicinski 5981580cbcbSJakub Kicinski static ssize_t 5991580cbcbSJakub Kicinski nsim_pp_hold_read(struct file *file, char __user *data, 6001580cbcbSJakub Kicinski size_t count, loff_t *ppos) 6011580cbcbSJakub Kicinski { 6021580cbcbSJakub Kicinski struct netdevsim *ns = file->private_data; 6031580cbcbSJakub Kicinski char buf[3] = "n\n"; 6041580cbcbSJakub Kicinski 6051580cbcbSJakub Kicinski if (ns->page) 6061580cbcbSJakub Kicinski buf[0] = 'y'; 6071580cbcbSJakub Kicinski 6081580cbcbSJakub Kicinski return simple_read_from_buffer(data, count, ppos, buf, 2); 6091580cbcbSJakub Kicinski } 6101580cbcbSJakub Kicinski 6111580cbcbSJakub Kicinski static ssize_t 6121580cbcbSJakub Kicinski nsim_pp_hold_write(struct file *file, const char __user *data, 6131580cbcbSJakub Kicinski size_t count, loff_t *ppos) 6141580cbcbSJakub Kicinski { 6151580cbcbSJakub Kicinski struct netdevsim *ns = file->private_data; 6161580cbcbSJakub Kicinski ssize_t ret; 6171580cbcbSJakub Kicinski bool val; 6181580cbcbSJakub Kicinski 6191580cbcbSJakub Kicinski ret = kstrtobool_from_user(data, count, &val); 6201580cbcbSJakub Kicinski if (ret) 6211580cbcbSJakub Kicinski return ret; 6221580cbcbSJakub Kicinski 6231580cbcbSJakub Kicinski rtnl_lock(); 6241580cbcbSJakub Kicinski ret = count; 6251580cbcbSJakub Kicinski if (val == !!ns->page) 6261580cbcbSJakub Kicinski goto exit; 6271580cbcbSJakub Kicinski 6281580cbcbSJakub Kicinski if (!netif_running(ns->netdev) && val) { 6291580cbcbSJakub Kicinski ret = -ENETDOWN; 6301580cbcbSJakub Kicinski } else if (val) { 6313762ec05SDavid Wei ns->page = page_pool_dev_alloc_pages(ns->rq[0].page_pool); 6321580cbcbSJakub Kicinski if (!ns->page) 6331580cbcbSJakub Kicinski ret = -ENOMEM; 6341580cbcbSJakub Kicinski } else { 6351580cbcbSJakub Kicinski page_pool_put_full_page(ns->page->pp, ns->page, false); 6361580cbcbSJakub Kicinski ns->page = NULL; 6371580cbcbSJakub Kicinski } 6381580cbcbSJakub Kicinski 6391580cbcbSJakub Kicinski exit: 640b9b8301dSEric Dumazet rtnl_unlock(); 641b9b8301dSEric Dumazet return ret; 6421580cbcbSJakub Kicinski } 6431580cbcbSJakub Kicinski 6441580cbcbSJakub Kicinski static const struct file_operations nsim_pp_hold_fops = { 6451580cbcbSJakub Kicinski .open = simple_open, 6461580cbcbSJakub Kicinski .read = nsim_pp_hold_read, 6471580cbcbSJakub Kicinski .write = nsim_pp_hold_write, 6481580cbcbSJakub Kicinski .llseek = generic_file_llseek, 6491580cbcbSJakub Kicinski .owner = THIS_MODULE, 6501580cbcbSJakub Kicinski }; 6511580cbcbSJakub Kicinski 65283c9e13aSJakub Kicinski static void nsim_setup(struct net_device *dev) 65383c9e13aSJakub Kicinski { 65483c9e13aSJakub Kicinski ether_setup(dev); 65583c9e13aSJakub Kicinski eth_hw_addr_random(dev); 65683c9e13aSJakub Kicinski 65783c9e13aSJakub Kicinski dev->tx_queue_len = 0; 65883c9e13aSJakub Kicinski dev->flags &= ~IFF_MULTICAST; 65983c9e13aSJakub Kicinski dev->priv_flags |= IFF_LIVE_ADDR_CHANGE | 66083c9e13aSJakub Kicinski IFF_NO_QUEUE; 66183c9e13aSJakub Kicinski dev->features |= NETIF_F_HIGHDMA | 66283c9e13aSJakub Kicinski NETIF_F_SG | 66383c9e13aSJakub Kicinski NETIF_F_FRAGLIST | 66483c9e13aSJakub Kicinski NETIF_F_HW_CSUM | 66583c9e13aSJakub Kicinski NETIF_F_TSO; 666494bd83bSSabrina Dubroca dev->hw_features |= NETIF_F_HW_TC | 667494bd83bSSabrina Dubroca NETIF_F_SG | 668494bd83bSSabrina Dubroca NETIF_F_FRAGLIST | 669494bd83bSSabrina Dubroca NETIF_F_HW_CSUM | 670494bd83bSSabrina Dubroca NETIF_F_TSO; 67183c9e13aSJakub Kicinski dev->max_mtu = ETH_MAX_MTU; 67266c0e13aSMarek Majtyka dev->xdp_features = NETDEV_XDP_ACT_HW_OFFLOAD; 67383c9e13aSJakub Kicinski } 67483c9e13aSJakub Kicinski 6753762ec05SDavid Wei static int nsim_queue_init(struct netdevsim *ns) 6763762ec05SDavid Wei { 6773762ec05SDavid Wei struct net_device *dev = ns->netdev; 6783762ec05SDavid Wei int i; 6793762ec05SDavid Wei 6803762ec05SDavid Wei ns->rq = kvcalloc(dev->num_rx_queues, sizeof(*ns->rq), 6813762ec05SDavid Wei GFP_KERNEL_ACCOUNT | __GFP_RETRY_MAYFAIL); 6823762ec05SDavid Wei if (!ns->rq) 6833762ec05SDavid Wei return -ENOMEM; 6843762ec05SDavid Wei 6853762ec05SDavid Wei for (i = 0; i < dev->num_rx_queues; i++) 6863762ec05SDavid Wei skb_queue_head_init(&ns->rq[i].skb_queue); 6873762ec05SDavid Wei 6883762ec05SDavid Wei return 0; 6893762ec05SDavid Wei } 6903762ec05SDavid Wei 6913762ec05SDavid Wei static void nsim_queue_free(struct netdevsim *ns) 6923762ec05SDavid Wei { 6933762ec05SDavid Wei struct net_device *dev = ns->netdev; 6943762ec05SDavid Wei int i; 6953762ec05SDavid Wei 6963762ec05SDavid Wei for (i = 0; i < dev->num_rx_queues; i++) 6973762ec05SDavid Wei skb_queue_purge_reason(&ns->rq[i].skb_queue, 6983762ec05SDavid Wei SKB_DROP_REASON_QUEUE_PURGE); 6993762ec05SDavid Wei 7003762ec05SDavid Wei kvfree(ns->rq); 7013762ec05SDavid Wei ns->rq = NULL; 7023762ec05SDavid Wei } 7033762ec05SDavid Wei 70492ba1f29SDmytro Linkin static int nsim_init_netdevsim(struct netdevsim *ns) 70592ba1f29SDmytro Linkin { 706b63e78fcSVladimir Oltean struct mock_phc *phc; 70792ba1f29SDmytro Linkin int err; 70892ba1f29SDmytro Linkin 709b63e78fcSVladimir Oltean phc = mock_phc_create(&ns->nsim_bus_dev->dev); 710b63e78fcSVladimir Oltean if (IS_ERR(phc)) 711b63e78fcSVladimir Oltean return PTR_ERR(phc); 712b63e78fcSVladimir Oltean 713b63e78fcSVladimir Oltean ns->phc = phc; 71492ba1f29SDmytro Linkin ns->netdev->netdev_ops = &nsim_netdev_ops; 715f216306bSJakub Kicinski ns->netdev->stat_ops = &nsim_stat_ops; 71692ba1f29SDmytro Linkin 71792ba1f29SDmytro Linkin err = nsim_udp_tunnels_info_create(ns->nsim_dev, ns->netdev); 71892ba1f29SDmytro Linkin if (err) 719b63e78fcSVladimir Oltean goto err_phc_destroy; 72092ba1f29SDmytro Linkin 72192ba1f29SDmytro Linkin rtnl_lock(); 7223762ec05SDavid Wei err = nsim_queue_init(ns); 72392ba1f29SDmytro Linkin if (err) 72492ba1f29SDmytro Linkin goto err_utn_destroy; 72592ba1f29SDmytro Linkin 7263762ec05SDavid Wei err = nsim_bpf_init(ns); 7273762ec05SDavid Wei if (err) 7283762ec05SDavid Wei goto err_rq_destroy; 7293762ec05SDavid Wei 73002b34d03SSabrina Dubroca nsim_macsec_init(ns); 73192ba1f29SDmytro Linkin nsim_ipsec_init(ns); 73292ba1f29SDmytro Linkin 73392ba1f29SDmytro Linkin err = register_netdevice(ns->netdev); 73492ba1f29SDmytro Linkin if (err) 73592ba1f29SDmytro Linkin goto err_ipsec_teardown; 73692ba1f29SDmytro Linkin rtnl_unlock(); 73792ba1f29SDmytro Linkin return 0; 73892ba1f29SDmytro Linkin 73992ba1f29SDmytro Linkin err_ipsec_teardown: 74092ba1f29SDmytro Linkin nsim_ipsec_teardown(ns); 74102b34d03SSabrina Dubroca nsim_macsec_teardown(ns); 74292ba1f29SDmytro Linkin nsim_bpf_uninit(ns); 7433762ec05SDavid Wei err_rq_destroy: 7443762ec05SDavid Wei nsim_queue_free(ns); 74592ba1f29SDmytro Linkin err_utn_destroy: 74692ba1f29SDmytro Linkin rtnl_unlock(); 74792ba1f29SDmytro Linkin nsim_udp_tunnels_info_destroy(ns->netdev); 748b63e78fcSVladimir Oltean err_phc_destroy: 749b63e78fcSVladimir Oltean mock_phc_destroy(ns->phc); 75092ba1f29SDmytro Linkin return err; 75192ba1f29SDmytro Linkin } 75292ba1f29SDmytro Linkin 75392ba1f29SDmytro Linkin static int nsim_init_netdevsim_vf(struct netdevsim *ns) 75492ba1f29SDmytro Linkin { 75592ba1f29SDmytro Linkin int err; 75692ba1f29SDmytro Linkin 75792ba1f29SDmytro Linkin ns->netdev->netdev_ops = &nsim_vf_netdev_ops; 75892ba1f29SDmytro Linkin rtnl_lock(); 75992ba1f29SDmytro Linkin err = register_netdevice(ns->netdev); 76092ba1f29SDmytro Linkin rtnl_unlock(); 76192ba1f29SDmytro Linkin return err; 76292ba1f29SDmytro Linkin } 76392ba1f29SDmytro Linkin 764ea937f77SJakub Kicinski static void nsim_exit_netdevsim(struct netdevsim *ns) 765ea937f77SJakub Kicinski { 766ea937f77SJakub Kicinski nsim_udp_tunnels_info_destroy(ns->netdev); 767ea937f77SJakub Kicinski mock_phc_destroy(ns->phc); 768ea937f77SJakub Kicinski } 769ea937f77SJakub Kicinski 770e05b2d14SJiri Pirko struct netdevsim * 771e05b2d14SJiri Pirko nsim_create(struct nsim_dev *nsim_dev, struct nsim_dev_port *nsim_dev_port) 77283c9e13aSJakub Kicinski { 773e05b2d14SJiri Pirko struct net_device *dev; 774e05b2d14SJiri Pirko struct netdevsim *ns; 775af9095f0SJiri Pirko int err; 776eeeaaf18SJakub Kicinski 777d4861fc6SPeilin Ye dev = alloc_netdev_mq(sizeof(*ns), "eth%d", NET_NAME_UNKNOWN, nsim_setup, 778d4861fc6SPeilin Ye nsim_dev->nsim_bus_dev->num_queues); 779e05b2d14SJiri Pirko if (!dev) 780e05b2d14SJiri Pirko return ERR_PTR(-ENOMEM); 781e05b2d14SJiri Pirko 78290d29913SJiri Pirko dev_net_set(dev, nsim_dev_net(nsim_dev)); 783e05b2d14SJiri Pirko ns = netdev_priv(dev); 7848320d145SJiri Pirko ns->netdev = dev; 785863a42b2SHillf Danton u64_stats_init(&ns->syncp); 786e05b2d14SJiri Pirko ns->nsim_dev = nsim_dev; 787e05b2d14SJiri Pirko ns->nsim_dev_port = nsim_dev_port; 788e05b2d14SJiri Pirko ns->nsim_bus_dev = nsim_dev->nsim_bus_dev; 78940e4fe4cSJiri Pirko SET_NETDEV_DEV(dev, &ns->nsim_bus_dev->dev); 790ac73d4bfSJiri Pirko SET_NETDEV_DEVLINK_PORT(dev, &nsim_dev_port->devlink_port); 791ff1f7c17SJakub Kicinski nsim_ethtool_init(ns); 79292ba1f29SDmytro Linkin if (nsim_dev_port_is_pf(nsim_dev_port)) 79392ba1f29SDmytro Linkin err = nsim_init_netdevsim(ns); 79492ba1f29SDmytro Linkin else 79592ba1f29SDmytro Linkin err = nsim_init_netdevsim_vf(ns); 796424be63aSJakub Kicinski if (err) 797424be63aSJakub Kicinski goto err_free_netdev; 7981580cbcbSJakub Kicinski 7991580cbcbSJakub Kicinski ns->pp_dfs = debugfs_create_file("pp_hold", 0600, nsim_dev_port->ddir, 8001580cbcbSJakub Kicinski ns, &nsim_pp_hold_fops); 8011580cbcbSJakub Kicinski 802e05b2d14SJiri Pirko return ns; 803e05b2d14SJiri Pirko 804e05b2d14SJiri Pirko err_free_netdev: 805e05b2d14SJiri Pirko free_netdev(dev); 806e05b2d14SJiri Pirko return ERR_PTR(err); 807e05b2d14SJiri Pirko } 808e05b2d14SJiri Pirko 809e05b2d14SJiri Pirko void nsim_destroy(struct netdevsim *ns) 810e05b2d14SJiri Pirko { 811e05b2d14SJiri Pirko struct net_device *dev = ns->netdev; 812f532957dSDavid Wei struct netdevsim *peer; 813e05b2d14SJiri Pirko 8141580cbcbSJakub Kicinski debugfs_remove(ns->pp_dfs); 8151580cbcbSJakub Kicinski 816e05b2d14SJiri Pirko rtnl_lock(); 817f532957dSDavid Wei peer = rtnl_dereference(ns->peer); 818f532957dSDavid Wei if (peer) 819f532957dSDavid Wei RCU_INIT_POINTER(peer->peer, NULL); 820f532957dSDavid Wei RCU_INIT_POINTER(ns->peer, NULL); 821e05b2d14SJiri Pirko unregister_netdevice(dev); 82292ba1f29SDmytro Linkin if (nsim_dev_port_is_pf(ns->nsim_dev_port)) { 82302b34d03SSabrina Dubroca nsim_macsec_teardown(ns); 824e05b2d14SJiri Pirko nsim_ipsec_teardown(ns); 825e05b2d14SJiri Pirko nsim_bpf_uninit(ns); 8263762ec05SDavid Wei nsim_queue_free(ns); 82792ba1f29SDmytro Linkin } 828e05b2d14SJiri Pirko rtnl_unlock(); 82992ba1f29SDmytro Linkin if (nsim_dev_port_is_pf(ns->nsim_dev_port)) 830ea937f77SJakub Kicinski nsim_exit_netdevsim(ns); 8311580cbcbSJakub Kicinski 8321580cbcbSJakub Kicinski /* Put this intentionally late to exercise the orphaning path */ 8331580cbcbSJakub Kicinski if (ns->page) { 8341580cbcbSJakub Kicinski page_pool_put_full_page(ns->page->pp, ns->page, false); 8351580cbcbSJakub Kicinski ns->page = NULL; 8361580cbcbSJakub Kicinski } 8371580cbcbSJakub Kicinski 838e05b2d14SJiri Pirko free_netdev(dev); 839e05b2d14SJiri Pirko } 840e05b2d14SJiri Pirko 841f532957dSDavid Wei bool netdev_is_nsim(struct net_device *dev) 842f532957dSDavid Wei { 843f532957dSDavid Wei return dev->netdev_ops == &nsim_netdev_ops; 844f532957dSDavid Wei } 845f532957dSDavid Wei 846e05b2d14SJiri Pirko static int nsim_validate(struct nlattr *tb[], struct nlattr *data[], 847e05b2d14SJiri Pirko struct netlink_ext_ack *extack) 848e05b2d14SJiri Pirko { 849d4861fc6SPeilin Ye NL_SET_ERR_MSG_MOD(extack, 850d4861fc6SPeilin Ye "Please use: echo \"[ID] [PORT_COUNT] [NUM_QUEUES]\" > /sys/bus/netdevsim/new_device"); 851e05b2d14SJiri Pirko return -EOPNOTSUPP; 852eeeaaf18SJakub Kicinski } 853eeeaaf18SJakub Kicinski 85483c9e13aSJakub Kicinski static struct rtnl_link_ops nsim_link_ops __read_mostly = { 85583c9e13aSJakub Kicinski .kind = DRV_NAME, 85683c9e13aSJakub Kicinski .validate = nsim_validate, 85783c9e13aSJakub Kicinski }; 85883c9e13aSJakub Kicinski 85983c9e13aSJakub Kicinski static int __init nsim_module_init(void) 86083c9e13aSJakub Kicinski { 86131d3ad83SJakub Kicinski int err; 86231d3ad83SJakub Kicinski 863d514f41eSJiri Pirko err = nsim_dev_init(); 864af9095f0SJiri Pirko if (err) 865ab1d0cc0SJiri Pirko return err; 866eeeaaf18SJakub Kicinski 867925f5afeSJiri Pirko err = nsim_bus_init(); 86831d3ad83SJakub Kicinski if (err) 869d514f41eSJiri Pirko goto err_dev_exit; 87031d3ad83SJakub Kicinski 871a5facc4cSJiri Pirko err = rtnl_link_register(&nsim_link_ops); 87279579220SJakub Kicinski if (err) 873925f5afeSJiri Pirko goto err_bus_exit; 87479579220SJakub Kicinski 87531d3ad83SJakub Kicinski return 0; 87631d3ad83SJakub Kicinski 877925f5afeSJiri Pirko err_bus_exit: 878925f5afeSJiri Pirko nsim_bus_exit(); 879d514f41eSJiri Pirko err_dev_exit: 880d514f41eSJiri Pirko nsim_dev_exit(); 88131d3ad83SJakub Kicinski return err; 88283c9e13aSJakub Kicinski } 88383c9e13aSJakub Kicinski 88483c9e13aSJakub Kicinski static void __exit nsim_module_exit(void) 88583c9e13aSJakub Kicinski { 88683c9e13aSJakub Kicinski rtnl_link_unregister(&nsim_link_ops); 887925f5afeSJiri Pirko nsim_bus_exit(); 888d514f41eSJiri Pirko nsim_dev_exit(); 88983c9e13aSJakub Kicinski } 89083c9e13aSJakub Kicinski 89183c9e13aSJakub Kicinski module_init(nsim_module_init); 89283c9e13aSJakub Kicinski module_exit(nsim_module_exit); 89383c9e13aSJakub Kicinski MODULE_LICENSE("GPL"); 8941fff1f79SJakub Kicinski MODULE_DESCRIPTION("Simulated networking device for testing"); 89583c9e13aSJakub Kicinski MODULE_ALIAS_RTNL_LINK(DRV_NAME); 896