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> 2531d3ad83SJakub Kicinski #include <net/pkt_cls.h> 2683c9e13aSJakub Kicinski #include <net/rtnetlink.h> 27424be63aSJakub Kicinski #include <net/udp_tunnel.h> 2883c9e13aSJakub Kicinski 2983c9e13aSJakub Kicinski #include "netdevsim.h" 3083c9e13aSJakub Kicinski 313762ec05SDavid Wei #define NSIM_RING_SIZE 256 323762ec05SDavid Wei 333762ec05SDavid Wei static int nsim_napi_rx(struct nsim_rq *rq, struct sk_buff *skb) 343762ec05SDavid Wei { 353762ec05SDavid Wei if (skb_queue_len(&rq->skb_queue) > NSIM_RING_SIZE) { 363762ec05SDavid Wei dev_kfree_skb_any(skb); 373762ec05SDavid Wei return NET_RX_DROP; 383762ec05SDavid Wei } 393762ec05SDavid Wei 403762ec05SDavid Wei skb_queue_tail(&rq->skb_queue, skb); 413762ec05SDavid Wei return NET_RX_SUCCESS; 423762ec05SDavid Wei } 433762ec05SDavid Wei 443762ec05SDavid Wei static int nsim_forward_skb(struct net_device *dev, struct sk_buff *skb, 453762ec05SDavid Wei struct nsim_rq *rq) 463762ec05SDavid Wei { 473762ec05SDavid Wei return __dev_forward_skb(dev, skb) ?: nsim_napi_rx(rq, skb); 483762ec05SDavid Wei } 493762ec05SDavid Wei 5083c9e13aSJakub Kicinski static netdev_tx_t nsim_start_xmit(struct sk_buff *skb, struct net_device *dev) 5183c9e13aSJakub Kicinski { 5283c9e13aSJakub Kicinski struct netdevsim *ns = netdev_priv(dev); 533762ec05SDavid Wei struct net_device *peer_dev; 549eb95228SDavid Wei unsigned int len = skb->len; 559eb95228SDavid Wei struct netdevsim *peer_ns; 563762ec05SDavid Wei struct nsim_rq *rq; 573762ec05SDavid Wei int rxq; 5883c9e13aSJakub Kicinski 599eb95228SDavid Wei rcu_read_lock(); 607699353dSShannon Nelson if (!nsim_ipsec_tx(ns, skb)) 619eb95228SDavid Wei goto out_drop_free; 627699353dSShannon Nelson 639eb95228SDavid Wei peer_ns = rcu_dereference(ns->peer); 649eb95228SDavid Wei if (!peer_ns) 659eb95228SDavid Wei goto out_drop_free; 669eb95228SDavid Wei 673762ec05SDavid Wei peer_dev = peer_ns->netdev; 683762ec05SDavid Wei rxq = skb_get_queue_mapping(skb); 693762ec05SDavid Wei if (rxq >= peer_dev->num_rx_queues) 703762ec05SDavid Wei rxq = rxq % peer_dev->num_rx_queues; 713762ec05SDavid Wei rq = &peer_ns->rq[rxq]; 723762ec05SDavid Wei 739eb95228SDavid Wei skb_tx_timestamp(skb); 743762ec05SDavid Wei if (unlikely(nsim_forward_skb(peer_dev, skb, rq) == NET_RX_DROP)) 759eb95228SDavid Wei goto out_drop_cnt; 769eb95228SDavid Wei 773762ec05SDavid Wei napi_schedule(&rq->napi); 783762ec05SDavid Wei 799eb95228SDavid Wei rcu_read_unlock(); 8083c9e13aSJakub Kicinski u64_stats_update_begin(&ns->syncp); 8183c9e13aSJakub Kicinski ns->tx_packets++; 829eb95228SDavid Wei ns->tx_bytes += len; 8383c9e13aSJakub Kicinski u64_stats_update_end(&ns->syncp); 849eb95228SDavid Wei return NETDEV_TX_OK; 8583c9e13aSJakub Kicinski 869eb95228SDavid Wei out_drop_free: 8783c9e13aSJakub Kicinski dev_kfree_skb(skb); 889eb95228SDavid Wei out_drop_cnt: 899eb95228SDavid Wei rcu_read_unlock(); 909eb95228SDavid Wei u64_stats_update_begin(&ns->syncp); 919eb95228SDavid Wei ns->tx_dropped++; 929eb95228SDavid Wei u64_stats_update_end(&ns->syncp); 9383c9e13aSJakub Kicinski return NETDEV_TX_OK; 9483c9e13aSJakub Kicinski } 9583c9e13aSJakub Kicinski 9683c9e13aSJakub Kicinski static void nsim_set_rx_mode(struct net_device *dev) 9783c9e13aSJakub Kicinski { 9883c9e13aSJakub Kicinski } 9983c9e13aSJakub Kicinski 10031d3ad83SJakub Kicinski static int nsim_change_mtu(struct net_device *dev, int new_mtu) 10131d3ad83SJakub Kicinski { 10231d3ad83SJakub Kicinski struct netdevsim *ns = netdev_priv(dev); 10331d3ad83SJakub Kicinski 104799e173dSJakub Kicinski if (ns->xdp.prog && new_mtu > NSIM_XDP_MAX_MTU) 10531d3ad83SJakub Kicinski return -EBUSY; 10631d3ad83SJakub Kicinski 1071eb2cdedSEric Dumazet WRITE_ONCE(dev->mtu, new_mtu); 10831d3ad83SJakub Kicinski 10931d3ad83SJakub Kicinski return 0; 11031d3ad83SJakub Kicinski } 11131d3ad83SJakub Kicinski 11283c9e13aSJakub Kicinski static void 11383c9e13aSJakub Kicinski nsim_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) 11483c9e13aSJakub Kicinski { 11583c9e13aSJakub Kicinski struct netdevsim *ns = netdev_priv(dev); 11683c9e13aSJakub Kicinski unsigned int start; 11783c9e13aSJakub Kicinski 11883c9e13aSJakub Kicinski do { 119068c38adSThomas Gleixner start = u64_stats_fetch_begin(&ns->syncp); 12083c9e13aSJakub Kicinski stats->tx_bytes = ns->tx_bytes; 12183c9e13aSJakub Kicinski stats->tx_packets = ns->tx_packets; 1229eb95228SDavid Wei stats->tx_dropped = ns->tx_dropped; 123068c38adSThomas Gleixner } while (u64_stats_fetch_retry(&ns->syncp, start)); 12483c9e13aSJakub Kicinski } 12583c9e13aSJakub Kicinski 12631d3ad83SJakub Kicinski static int 12731d3ad83SJakub Kicinski nsim_setup_tc_block_cb(enum tc_setup_type type, void *type_data, void *cb_priv) 12831d3ad83SJakub Kicinski { 12931d3ad83SJakub Kicinski return nsim_bpf_setup_tc_block_cb(type, type_data, cb_priv); 13031d3ad83SJakub Kicinski } 13131d3ad83SJakub Kicinski 13279579220SJakub Kicinski static int nsim_set_vf_mac(struct net_device *dev, int vf, u8 *mac) 13379579220SJakub Kicinski { 13479579220SJakub Kicinski struct netdevsim *ns = netdev_priv(dev); 1355e388f3dSJakub Kicinski struct nsim_dev *nsim_dev = ns->nsim_dev; 13679579220SJakub Kicinski 13779579220SJakub Kicinski /* Only refuse multicast addresses, zero address can mean unset/any. */ 1385e388f3dSJakub Kicinski if (vf >= nsim_dev_get_vfs(nsim_dev) || is_multicast_ether_addr(mac)) 13979579220SJakub Kicinski return -EINVAL; 1405e388f3dSJakub Kicinski memcpy(nsim_dev->vfconfigs[vf].vf_mac, mac, ETH_ALEN); 14179579220SJakub Kicinski 14279579220SJakub Kicinski return 0; 14379579220SJakub Kicinski } 14479579220SJakub Kicinski 14579579220SJakub Kicinski static int nsim_set_vf_vlan(struct net_device *dev, int vf, 14679579220SJakub Kicinski u16 vlan, u8 qos, __be16 vlan_proto) 14779579220SJakub Kicinski { 14879579220SJakub Kicinski struct netdevsim *ns = netdev_priv(dev); 1495e388f3dSJakub Kicinski struct nsim_dev *nsim_dev = ns->nsim_dev; 15079579220SJakub Kicinski 1515e388f3dSJakub Kicinski if (vf >= nsim_dev_get_vfs(nsim_dev) || vlan > 4095 || qos > 7) 15279579220SJakub Kicinski return -EINVAL; 15379579220SJakub Kicinski 1545e388f3dSJakub Kicinski nsim_dev->vfconfigs[vf].vlan = vlan; 1555e388f3dSJakub Kicinski nsim_dev->vfconfigs[vf].qos = qos; 1565e388f3dSJakub Kicinski nsim_dev->vfconfigs[vf].vlan_proto = vlan_proto; 15779579220SJakub Kicinski 15879579220SJakub Kicinski return 0; 15979579220SJakub Kicinski } 16079579220SJakub Kicinski 16179579220SJakub Kicinski static int nsim_set_vf_rate(struct net_device *dev, int vf, int min, int max) 16279579220SJakub Kicinski { 16379579220SJakub Kicinski struct netdevsim *ns = netdev_priv(dev); 1645e388f3dSJakub Kicinski struct nsim_dev *nsim_dev = ns->nsim_dev; 16579579220SJakub Kicinski 166160dc373SDmytro Linkin if (nsim_esw_mode_is_switchdev(ns->nsim_dev)) { 167160dc373SDmytro Linkin pr_err("Not supported in switchdev mode. Please use devlink API.\n"); 168160dc373SDmytro Linkin return -EOPNOTSUPP; 169160dc373SDmytro Linkin } 170160dc373SDmytro Linkin 1715e388f3dSJakub Kicinski if (vf >= nsim_dev_get_vfs(nsim_dev)) 17279579220SJakub Kicinski return -EINVAL; 17379579220SJakub Kicinski 1745e388f3dSJakub Kicinski nsim_dev->vfconfigs[vf].min_tx_rate = min; 1755e388f3dSJakub Kicinski nsim_dev->vfconfigs[vf].max_tx_rate = max; 17679579220SJakub Kicinski 17779579220SJakub Kicinski return 0; 17879579220SJakub Kicinski } 17979579220SJakub Kicinski 18079579220SJakub Kicinski static int nsim_set_vf_spoofchk(struct net_device *dev, int vf, bool val) 18179579220SJakub Kicinski { 18279579220SJakub Kicinski struct netdevsim *ns = netdev_priv(dev); 1835e388f3dSJakub Kicinski struct nsim_dev *nsim_dev = ns->nsim_dev; 18479579220SJakub Kicinski 1855e388f3dSJakub Kicinski if (vf >= nsim_dev_get_vfs(nsim_dev)) 18679579220SJakub Kicinski return -EINVAL; 1875e388f3dSJakub Kicinski nsim_dev->vfconfigs[vf].spoofchk_enabled = val; 18879579220SJakub Kicinski 18979579220SJakub Kicinski return 0; 19079579220SJakub Kicinski } 19179579220SJakub Kicinski 19279579220SJakub Kicinski static int nsim_set_vf_rss_query_en(struct net_device *dev, int vf, bool val) 19379579220SJakub Kicinski { 19479579220SJakub Kicinski struct netdevsim *ns = netdev_priv(dev); 1955e388f3dSJakub Kicinski struct nsim_dev *nsim_dev = ns->nsim_dev; 19679579220SJakub Kicinski 1975e388f3dSJakub Kicinski if (vf >= nsim_dev_get_vfs(nsim_dev)) 19879579220SJakub Kicinski return -EINVAL; 1995e388f3dSJakub Kicinski nsim_dev->vfconfigs[vf].rss_query_enabled = val; 20079579220SJakub Kicinski 20179579220SJakub Kicinski return 0; 20279579220SJakub Kicinski } 20379579220SJakub Kicinski 20479579220SJakub Kicinski static int nsim_set_vf_trust(struct net_device *dev, int vf, bool val) 20579579220SJakub Kicinski { 20679579220SJakub Kicinski struct netdevsim *ns = netdev_priv(dev); 2075e388f3dSJakub Kicinski struct nsim_dev *nsim_dev = ns->nsim_dev; 20879579220SJakub Kicinski 2095e388f3dSJakub Kicinski if (vf >= nsim_dev_get_vfs(nsim_dev)) 21079579220SJakub Kicinski return -EINVAL; 2115e388f3dSJakub Kicinski nsim_dev->vfconfigs[vf].trusted = val; 21279579220SJakub Kicinski 21379579220SJakub Kicinski return 0; 21479579220SJakub Kicinski } 21579579220SJakub Kicinski 21679579220SJakub Kicinski static int 21779579220SJakub Kicinski nsim_get_vf_config(struct net_device *dev, int vf, struct ifla_vf_info *ivi) 21879579220SJakub Kicinski { 21979579220SJakub Kicinski struct netdevsim *ns = netdev_priv(dev); 2205e388f3dSJakub Kicinski struct nsim_dev *nsim_dev = ns->nsim_dev; 22179579220SJakub Kicinski 2225e388f3dSJakub Kicinski if (vf >= nsim_dev_get_vfs(nsim_dev)) 22379579220SJakub Kicinski return -EINVAL; 22479579220SJakub Kicinski 22579579220SJakub Kicinski ivi->vf = vf; 2265e388f3dSJakub Kicinski ivi->linkstate = nsim_dev->vfconfigs[vf].link_state; 2275e388f3dSJakub Kicinski ivi->min_tx_rate = nsim_dev->vfconfigs[vf].min_tx_rate; 2285e388f3dSJakub Kicinski ivi->max_tx_rate = nsim_dev->vfconfigs[vf].max_tx_rate; 2295e388f3dSJakub Kicinski ivi->vlan = nsim_dev->vfconfigs[vf].vlan; 2305e388f3dSJakub Kicinski ivi->vlan_proto = nsim_dev->vfconfigs[vf].vlan_proto; 2315e388f3dSJakub Kicinski ivi->qos = nsim_dev->vfconfigs[vf].qos; 2325e388f3dSJakub Kicinski memcpy(&ivi->mac, nsim_dev->vfconfigs[vf].vf_mac, ETH_ALEN); 2335e388f3dSJakub Kicinski ivi->spoofchk = nsim_dev->vfconfigs[vf].spoofchk_enabled; 2345e388f3dSJakub Kicinski ivi->trusted = nsim_dev->vfconfigs[vf].trusted; 2355e388f3dSJakub Kicinski ivi->rss_query_en = nsim_dev->vfconfigs[vf].rss_query_enabled; 23679579220SJakub Kicinski 23779579220SJakub Kicinski return 0; 23879579220SJakub Kicinski } 23979579220SJakub Kicinski 24079579220SJakub Kicinski static int nsim_set_vf_link_state(struct net_device *dev, int vf, int state) 24179579220SJakub Kicinski { 24279579220SJakub Kicinski struct netdevsim *ns = netdev_priv(dev); 2435e388f3dSJakub Kicinski struct nsim_dev *nsim_dev = ns->nsim_dev; 24479579220SJakub Kicinski 2455e388f3dSJakub Kicinski if (vf >= nsim_dev_get_vfs(nsim_dev)) 24679579220SJakub Kicinski return -EINVAL; 24779579220SJakub Kicinski 24879579220SJakub Kicinski switch (state) { 24979579220SJakub Kicinski case IFLA_VF_LINK_STATE_AUTO: 25079579220SJakub Kicinski case IFLA_VF_LINK_STATE_ENABLE: 25179579220SJakub Kicinski case IFLA_VF_LINK_STATE_DISABLE: 25279579220SJakub Kicinski break; 25379579220SJakub Kicinski default: 25479579220SJakub Kicinski return -EINVAL; 25579579220SJakub Kicinski } 25679579220SJakub Kicinski 2575e388f3dSJakub Kicinski nsim_dev->vfconfigs[vf].link_state = state; 25879579220SJakub Kicinski 25979579220SJakub Kicinski return 0; 26079579220SJakub Kicinski } 26179579220SJakub Kicinski 26235da47feSVladimir Oltean static void nsim_taprio_stats(struct tc_taprio_qopt_stats *stats) 26335da47feSVladimir Oltean { 26435da47feSVladimir Oltean stats->window_drops = 0; 26535da47feSVladimir Oltean stats->tx_overruns = 0; 26635da47feSVladimir Oltean } 26735da47feSVladimir Oltean 26835da47feSVladimir Oltean static int nsim_setup_tc_taprio(struct net_device *dev, 26935da47feSVladimir Oltean struct tc_taprio_qopt_offload *offload) 27035da47feSVladimir Oltean { 27135da47feSVladimir Oltean int err = 0; 27235da47feSVladimir Oltean 27335da47feSVladimir Oltean switch (offload->cmd) { 27435da47feSVladimir Oltean case TAPRIO_CMD_REPLACE: 27535da47feSVladimir Oltean case TAPRIO_CMD_DESTROY: 27635da47feSVladimir Oltean break; 27735da47feSVladimir Oltean case TAPRIO_CMD_STATS: 27835da47feSVladimir Oltean nsim_taprio_stats(&offload->stats); 27935da47feSVladimir Oltean break; 28035da47feSVladimir Oltean default: 28135da47feSVladimir Oltean err = -EOPNOTSUPP; 28235da47feSVladimir Oltean } 28335da47feSVladimir Oltean 28435da47feSVladimir Oltean return err; 28535da47feSVladimir Oltean } 28635da47feSVladimir Oltean 287955bcb6eSPablo Neira Ayuso static LIST_HEAD(nsim_block_cb_list); 288955bcb6eSPablo Neira Ayuso 28931d3ad83SJakub Kicinski static int 29031d3ad83SJakub Kicinski nsim_setup_tc(struct net_device *dev, enum tc_setup_type type, void *type_data) 29131d3ad83SJakub Kicinski { 2924e95bc26SPablo Neira Ayuso struct netdevsim *ns = netdev_priv(dev); 2934e95bc26SPablo Neira Ayuso 29431d3ad83SJakub Kicinski switch (type) { 29535da47feSVladimir Oltean case TC_SETUP_QDISC_TAPRIO: 29635da47feSVladimir Oltean return nsim_setup_tc_taprio(dev, type_data); 29731d3ad83SJakub Kicinski case TC_SETUP_BLOCK: 298955bcb6eSPablo Neira Ayuso return flow_block_cb_setup_simple(type_data, 299955bcb6eSPablo Neira Ayuso &nsim_block_cb_list, 3004e95bc26SPablo Neira Ayuso nsim_setup_tc_block_cb, 3014e95bc26SPablo Neira Ayuso ns, ns, true); 30231d3ad83SJakub Kicinski default: 30331d3ad83SJakub Kicinski return -EOPNOTSUPP; 30431d3ad83SJakub Kicinski } 30531d3ad83SJakub Kicinski } 30631d3ad83SJakub Kicinski 30731d3ad83SJakub Kicinski static int 30831d3ad83SJakub Kicinski nsim_set_features(struct net_device *dev, netdev_features_t features) 30931d3ad83SJakub Kicinski { 31031d3ad83SJakub Kicinski struct netdevsim *ns = netdev_priv(dev); 31131d3ad83SJakub Kicinski 31231d3ad83SJakub Kicinski if ((dev->features & NETIF_F_HW_TC) > (features & NETIF_F_HW_TC)) 31331d3ad83SJakub Kicinski return nsim_bpf_disable_tc(ns); 31431d3ad83SJakub Kicinski 31531d3ad83SJakub Kicinski return 0; 31631d3ad83SJakub Kicinski } 31731d3ad83SJakub Kicinski 3188debcf58SDavid Wei static int nsim_get_iflink(const struct net_device *dev) 3198debcf58SDavid Wei { 3208debcf58SDavid Wei struct netdevsim *nsim, *peer; 3218debcf58SDavid Wei int iflink; 3228debcf58SDavid Wei 3238debcf58SDavid Wei nsim = netdev_priv(dev); 3248debcf58SDavid Wei 3258debcf58SDavid Wei rcu_read_lock(); 3268debcf58SDavid Wei peer = rcu_dereference(nsim->peer); 327*5add2f72SDavid Wei iflink = peer ? READ_ONCE(peer->netdev->ifindex) : 328*5add2f72SDavid Wei READ_ONCE(dev->ifindex); 3298debcf58SDavid Wei rcu_read_unlock(); 3308debcf58SDavid Wei 3318debcf58SDavid Wei return iflink; 3328debcf58SDavid Wei } 3338debcf58SDavid Wei 3343762ec05SDavid Wei static int nsim_rcv(struct nsim_rq *rq, int budget) 3353762ec05SDavid Wei { 3363762ec05SDavid Wei struct sk_buff *skb; 3373762ec05SDavid Wei int i; 3383762ec05SDavid Wei 3393762ec05SDavid Wei for (i = 0; i < budget; i++) { 3403762ec05SDavid Wei if (skb_queue_empty(&rq->skb_queue)) 3413762ec05SDavid Wei break; 3423762ec05SDavid Wei 3433762ec05SDavid Wei skb = skb_dequeue(&rq->skb_queue); 3443762ec05SDavid Wei netif_receive_skb(skb); 3453762ec05SDavid Wei } 3463762ec05SDavid Wei 3473762ec05SDavid Wei return i; 3483762ec05SDavid Wei } 3493762ec05SDavid Wei 3503762ec05SDavid Wei static int nsim_poll(struct napi_struct *napi, int budget) 3513762ec05SDavid Wei { 3523762ec05SDavid Wei struct nsim_rq *rq = container_of(napi, struct nsim_rq, napi); 3533762ec05SDavid Wei int done; 3543762ec05SDavid Wei 3553762ec05SDavid Wei done = nsim_rcv(rq, budget); 3563762ec05SDavid Wei napi_complete(napi); 3573762ec05SDavid Wei 3583762ec05SDavid Wei return done; 3593762ec05SDavid Wei } 3603762ec05SDavid Wei 3613762ec05SDavid Wei static int nsim_create_page_pool(struct nsim_rq *rq) 3623762ec05SDavid Wei { 3633762ec05SDavid Wei struct page_pool_params p = { 3643762ec05SDavid Wei .order = 0, 3653762ec05SDavid Wei .pool_size = NSIM_RING_SIZE, 3663762ec05SDavid Wei .nid = NUMA_NO_NODE, 3673762ec05SDavid Wei .dev = &rq->napi.dev->dev, 3683762ec05SDavid Wei .napi = &rq->napi, 3693762ec05SDavid Wei .dma_dir = DMA_BIDIRECTIONAL, 3703762ec05SDavid Wei .netdev = rq->napi.dev, 3713762ec05SDavid Wei }; 3723762ec05SDavid Wei 3733762ec05SDavid Wei rq->page_pool = page_pool_create(&p); 3743762ec05SDavid Wei if (IS_ERR(rq->page_pool)) { 3753762ec05SDavid Wei int err = PTR_ERR(rq->page_pool); 3763762ec05SDavid Wei 3773762ec05SDavid Wei rq->page_pool = NULL; 3783762ec05SDavid Wei return err; 3793762ec05SDavid Wei } 3803762ec05SDavid Wei return 0; 3813762ec05SDavid Wei } 3823762ec05SDavid Wei 3833762ec05SDavid Wei static int nsim_init_napi(struct netdevsim *ns) 3843762ec05SDavid Wei { 3853762ec05SDavid Wei struct net_device *dev = ns->netdev; 3863762ec05SDavid Wei struct nsim_rq *rq; 3873762ec05SDavid Wei int err, i; 3883762ec05SDavid Wei 3893762ec05SDavid Wei for (i = 0; i < dev->num_rx_queues; i++) { 3903762ec05SDavid Wei rq = &ns->rq[i]; 3913762ec05SDavid Wei 3923762ec05SDavid Wei netif_napi_add(dev, &rq->napi, nsim_poll); 3933762ec05SDavid Wei } 3943762ec05SDavid Wei 3953762ec05SDavid Wei for (i = 0; i < dev->num_rx_queues; i++) { 3963762ec05SDavid Wei rq = &ns->rq[i]; 3973762ec05SDavid Wei 3983762ec05SDavid Wei err = nsim_create_page_pool(rq); 3993762ec05SDavid Wei if (err) 4003762ec05SDavid Wei goto err_pp_destroy; 4013762ec05SDavid Wei } 4023762ec05SDavid Wei 4033762ec05SDavid Wei return 0; 4043762ec05SDavid Wei 4053762ec05SDavid Wei err_pp_destroy: 4063762ec05SDavid Wei while (i--) { 4073762ec05SDavid Wei page_pool_destroy(ns->rq[i].page_pool); 4083762ec05SDavid Wei ns->rq[i].page_pool = NULL; 4093762ec05SDavid Wei } 4103762ec05SDavid Wei 4113762ec05SDavid Wei for (i = 0; i < dev->num_rx_queues; i++) 4123762ec05SDavid Wei __netif_napi_del(&ns->rq[i].napi); 4133762ec05SDavid Wei 4143762ec05SDavid Wei return err; 4153762ec05SDavid Wei } 4163762ec05SDavid Wei 4173762ec05SDavid Wei static void nsim_enable_napi(struct netdevsim *ns) 4183762ec05SDavid Wei { 4193762ec05SDavid Wei struct net_device *dev = ns->netdev; 4203762ec05SDavid Wei int i; 4213762ec05SDavid Wei 4223762ec05SDavid Wei for (i = 0; i < dev->num_rx_queues; i++) { 4233762ec05SDavid Wei struct nsim_rq *rq = &ns->rq[i]; 4243762ec05SDavid Wei 4253762ec05SDavid Wei netif_queue_set_napi(dev, i, NETDEV_QUEUE_TYPE_RX, &rq->napi); 4263762ec05SDavid Wei napi_enable(&rq->napi); 4273762ec05SDavid Wei } 4283762ec05SDavid Wei } 4293762ec05SDavid Wei 4301580cbcbSJakub Kicinski static int nsim_open(struct net_device *dev) 4311580cbcbSJakub Kicinski { 4321580cbcbSJakub Kicinski struct netdevsim *ns = netdev_priv(dev); 4333762ec05SDavid Wei int err; 4341580cbcbSJakub Kicinski 4353762ec05SDavid Wei err = nsim_init_napi(ns); 4363762ec05SDavid Wei if (err) 4373762ec05SDavid Wei return err; 4381580cbcbSJakub Kicinski 4393762ec05SDavid Wei nsim_enable_napi(ns); 4403762ec05SDavid Wei 4413762ec05SDavid Wei return 0; 4423762ec05SDavid Wei } 4433762ec05SDavid Wei 4443762ec05SDavid Wei static void nsim_del_napi(struct netdevsim *ns) 4453762ec05SDavid Wei { 4463762ec05SDavid Wei struct net_device *dev = ns->netdev; 4473762ec05SDavid Wei int i; 4483762ec05SDavid Wei 4493762ec05SDavid Wei for (i = 0; i < dev->num_rx_queues; i++) { 4503762ec05SDavid Wei struct nsim_rq *rq = &ns->rq[i]; 4513762ec05SDavid Wei 4523762ec05SDavid Wei napi_disable(&rq->napi); 4533762ec05SDavid Wei __netif_napi_del(&rq->napi); 4543762ec05SDavid Wei } 4553762ec05SDavid Wei synchronize_net(); 4563762ec05SDavid Wei 4573762ec05SDavid Wei for (i = 0; i < dev->num_rx_queues; i++) { 4583762ec05SDavid Wei page_pool_destroy(ns->rq[i].page_pool); 4593762ec05SDavid Wei ns->rq[i].page_pool = NULL; 4603762ec05SDavid Wei } 4611580cbcbSJakub Kicinski } 4621580cbcbSJakub Kicinski 4631580cbcbSJakub Kicinski static int nsim_stop(struct net_device *dev) 4641580cbcbSJakub Kicinski { 4651580cbcbSJakub Kicinski struct netdevsim *ns = netdev_priv(dev); 4663762ec05SDavid Wei struct netdevsim *peer; 4671580cbcbSJakub Kicinski 4683762ec05SDavid Wei netif_carrier_off(dev); 4693762ec05SDavid Wei peer = rtnl_dereference(ns->peer); 4703762ec05SDavid Wei if (peer) 4713762ec05SDavid Wei netif_carrier_off(peer->netdev); 4723762ec05SDavid Wei 4733762ec05SDavid Wei nsim_del_napi(ns); 4741580cbcbSJakub Kicinski 4751580cbcbSJakub Kicinski return 0; 4761580cbcbSJakub Kicinski } 4771580cbcbSJakub Kicinski 47883c9e13aSJakub Kicinski static const struct net_device_ops nsim_netdev_ops = { 47983c9e13aSJakub Kicinski .ndo_start_xmit = nsim_start_xmit, 48083c9e13aSJakub Kicinski .ndo_set_rx_mode = nsim_set_rx_mode, 48183c9e13aSJakub Kicinski .ndo_set_mac_address = eth_mac_addr, 48283c9e13aSJakub Kicinski .ndo_validate_addr = eth_validate_addr, 48331d3ad83SJakub Kicinski .ndo_change_mtu = nsim_change_mtu, 48483c9e13aSJakub Kicinski .ndo_get_stats64 = nsim_get_stats64, 48579579220SJakub Kicinski .ndo_set_vf_mac = nsim_set_vf_mac, 48679579220SJakub Kicinski .ndo_set_vf_vlan = nsim_set_vf_vlan, 48779579220SJakub Kicinski .ndo_set_vf_rate = nsim_set_vf_rate, 48879579220SJakub Kicinski .ndo_set_vf_spoofchk = nsim_set_vf_spoofchk, 48979579220SJakub Kicinski .ndo_set_vf_trust = nsim_set_vf_trust, 49079579220SJakub Kicinski .ndo_get_vf_config = nsim_get_vf_config, 49179579220SJakub Kicinski .ndo_set_vf_link_state = nsim_set_vf_link_state, 49279579220SJakub Kicinski .ndo_set_vf_rss_query_en = nsim_set_vf_rss_query_en, 49331d3ad83SJakub Kicinski .ndo_setup_tc = nsim_setup_tc, 49431d3ad83SJakub Kicinski .ndo_set_features = nsim_set_features, 4958debcf58SDavid Wei .ndo_get_iflink = nsim_get_iflink, 49631d3ad83SJakub Kicinski .ndo_bpf = nsim_bpf, 4971580cbcbSJakub Kicinski .ndo_open = nsim_open, 4981580cbcbSJakub Kicinski .ndo_stop = nsim_stop, 49983c9e13aSJakub Kicinski }; 50083c9e13aSJakub Kicinski 50192ba1f29SDmytro Linkin static const struct net_device_ops nsim_vf_netdev_ops = { 50292ba1f29SDmytro Linkin .ndo_start_xmit = nsim_start_xmit, 50392ba1f29SDmytro Linkin .ndo_set_rx_mode = nsim_set_rx_mode, 50492ba1f29SDmytro Linkin .ndo_set_mac_address = eth_mac_addr, 50592ba1f29SDmytro Linkin .ndo_validate_addr = eth_validate_addr, 50692ba1f29SDmytro Linkin .ndo_change_mtu = nsim_change_mtu, 50792ba1f29SDmytro Linkin .ndo_get_stats64 = nsim_get_stats64, 50892ba1f29SDmytro Linkin .ndo_setup_tc = nsim_setup_tc, 50992ba1f29SDmytro Linkin .ndo_set_features = nsim_set_features, 51092ba1f29SDmytro Linkin }; 51192ba1f29SDmytro Linkin 512f216306bSJakub Kicinski /* We don't have true per-queue stats, yet, so do some random fakery here. 513f216306bSJakub Kicinski * Only report stuff for queue 0. 514f216306bSJakub Kicinski */ 515f216306bSJakub Kicinski static void nsim_get_queue_stats_rx(struct net_device *dev, int idx, 516f216306bSJakub Kicinski struct netdev_queue_stats_rx *stats) 517f216306bSJakub Kicinski { 518f216306bSJakub Kicinski struct rtnl_link_stats64 rtstats = {}; 519f216306bSJakub Kicinski 520f216306bSJakub Kicinski if (!idx) 521f216306bSJakub Kicinski nsim_get_stats64(dev, &rtstats); 522f216306bSJakub Kicinski 523f216306bSJakub Kicinski stats->packets = rtstats.rx_packets - !!rtstats.rx_packets; 524f216306bSJakub Kicinski stats->bytes = rtstats.rx_bytes; 525f216306bSJakub Kicinski } 526f216306bSJakub Kicinski 527f216306bSJakub Kicinski static void nsim_get_queue_stats_tx(struct net_device *dev, int idx, 528f216306bSJakub Kicinski struct netdev_queue_stats_tx *stats) 529f216306bSJakub Kicinski { 530f216306bSJakub Kicinski struct rtnl_link_stats64 rtstats = {}; 531f216306bSJakub Kicinski 532f216306bSJakub Kicinski if (!idx) 533f216306bSJakub Kicinski nsim_get_stats64(dev, &rtstats); 534f216306bSJakub Kicinski 535f216306bSJakub Kicinski stats->packets = rtstats.tx_packets - !!rtstats.tx_packets; 536f216306bSJakub Kicinski stats->bytes = rtstats.tx_bytes; 537f216306bSJakub Kicinski } 538f216306bSJakub Kicinski 539f216306bSJakub Kicinski static void nsim_get_base_stats(struct net_device *dev, 540f216306bSJakub Kicinski struct netdev_queue_stats_rx *rx, 541f216306bSJakub Kicinski struct netdev_queue_stats_tx *tx) 542f216306bSJakub Kicinski { 543f216306bSJakub Kicinski struct rtnl_link_stats64 rtstats = {}; 544f216306bSJakub Kicinski 545f216306bSJakub Kicinski nsim_get_stats64(dev, &rtstats); 546f216306bSJakub Kicinski 547f216306bSJakub Kicinski rx->packets = !!rtstats.rx_packets; 548f216306bSJakub Kicinski rx->bytes = 0; 549f216306bSJakub Kicinski tx->packets = !!rtstats.tx_packets; 550f216306bSJakub Kicinski tx->bytes = 0; 551f216306bSJakub Kicinski } 552f216306bSJakub Kicinski 553f216306bSJakub Kicinski static const struct netdev_stat_ops nsim_stat_ops = { 554f216306bSJakub Kicinski .get_queue_stats_tx = nsim_get_queue_stats_tx, 555f216306bSJakub Kicinski .get_queue_stats_rx = nsim_get_queue_stats_rx, 556f216306bSJakub Kicinski .get_base_stats = nsim_get_base_stats, 557f216306bSJakub Kicinski }; 558f216306bSJakub Kicinski 5591580cbcbSJakub Kicinski static ssize_t 5601580cbcbSJakub Kicinski nsim_pp_hold_read(struct file *file, char __user *data, 5611580cbcbSJakub Kicinski size_t count, loff_t *ppos) 5621580cbcbSJakub Kicinski { 5631580cbcbSJakub Kicinski struct netdevsim *ns = file->private_data; 5641580cbcbSJakub Kicinski char buf[3] = "n\n"; 5651580cbcbSJakub Kicinski 5661580cbcbSJakub Kicinski if (ns->page) 5671580cbcbSJakub Kicinski buf[0] = 'y'; 5681580cbcbSJakub Kicinski 5691580cbcbSJakub Kicinski return simple_read_from_buffer(data, count, ppos, buf, 2); 5701580cbcbSJakub Kicinski } 5711580cbcbSJakub Kicinski 5721580cbcbSJakub Kicinski static ssize_t 5731580cbcbSJakub Kicinski nsim_pp_hold_write(struct file *file, const char __user *data, 5741580cbcbSJakub Kicinski size_t count, loff_t *ppos) 5751580cbcbSJakub Kicinski { 5761580cbcbSJakub Kicinski struct netdevsim *ns = file->private_data; 5771580cbcbSJakub Kicinski ssize_t ret; 5781580cbcbSJakub Kicinski bool val; 5791580cbcbSJakub Kicinski 5801580cbcbSJakub Kicinski ret = kstrtobool_from_user(data, count, &val); 5811580cbcbSJakub Kicinski if (ret) 5821580cbcbSJakub Kicinski return ret; 5831580cbcbSJakub Kicinski 5841580cbcbSJakub Kicinski rtnl_lock(); 5851580cbcbSJakub Kicinski ret = count; 5861580cbcbSJakub Kicinski if (val == !!ns->page) 5871580cbcbSJakub Kicinski goto exit; 5881580cbcbSJakub Kicinski 5891580cbcbSJakub Kicinski if (!netif_running(ns->netdev) && val) { 5901580cbcbSJakub Kicinski ret = -ENETDOWN; 5911580cbcbSJakub Kicinski } else if (val) { 5923762ec05SDavid Wei ns->page = page_pool_dev_alloc_pages(ns->rq[0].page_pool); 5931580cbcbSJakub Kicinski if (!ns->page) 5941580cbcbSJakub Kicinski ret = -ENOMEM; 5951580cbcbSJakub Kicinski } else { 5961580cbcbSJakub Kicinski page_pool_put_full_page(ns->page->pp, ns->page, false); 5971580cbcbSJakub Kicinski ns->page = NULL; 5981580cbcbSJakub Kicinski } 5991580cbcbSJakub Kicinski rtnl_unlock(); 6001580cbcbSJakub Kicinski 6011580cbcbSJakub Kicinski exit: 6021580cbcbSJakub Kicinski return count; 6031580cbcbSJakub Kicinski } 6041580cbcbSJakub Kicinski 6051580cbcbSJakub Kicinski static const struct file_operations nsim_pp_hold_fops = { 6061580cbcbSJakub Kicinski .open = simple_open, 6071580cbcbSJakub Kicinski .read = nsim_pp_hold_read, 6081580cbcbSJakub Kicinski .write = nsim_pp_hold_write, 6091580cbcbSJakub Kicinski .llseek = generic_file_llseek, 6101580cbcbSJakub Kicinski .owner = THIS_MODULE, 6111580cbcbSJakub Kicinski }; 6121580cbcbSJakub Kicinski 61383c9e13aSJakub Kicinski static void nsim_setup(struct net_device *dev) 61483c9e13aSJakub Kicinski { 61583c9e13aSJakub Kicinski ether_setup(dev); 61683c9e13aSJakub Kicinski eth_hw_addr_random(dev); 61783c9e13aSJakub Kicinski 61883c9e13aSJakub Kicinski dev->tx_queue_len = 0; 61983c9e13aSJakub Kicinski dev->flags &= ~IFF_MULTICAST; 62083c9e13aSJakub Kicinski dev->priv_flags |= IFF_LIVE_ADDR_CHANGE | 62183c9e13aSJakub Kicinski IFF_NO_QUEUE; 62283c9e13aSJakub Kicinski dev->features |= NETIF_F_HIGHDMA | 62383c9e13aSJakub Kicinski NETIF_F_SG | 62483c9e13aSJakub Kicinski NETIF_F_FRAGLIST | 62583c9e13aSJakub Kicinski NETIF_F_HW_CSUM | 62683c9e13aSJakub Kicinski NETIF_F_TSO; 62731d3ad83SJakub Kicinski dev->hw_features |= NETIF_F_HW_TC; 62883c9e13aSJakub Kicinski dev->max_mtu = ETH_MAX_MTU; 62966c0e13aSMarek Majtyka dev->xdp_features = NETDEV_XDP_ACT_HW_OFFLOAD; 63083c9e13aSJakub Kicinski } 63183c9e13aSJakub Kicinski 6323762ec05SDavid Wei static int nsim_queue_init(struct netdevsim *ns) 6333762ec05SDavid Wei { 6343762ec05SDavid Wei struct net_device *dev = ns->netdev; 6353762ec05SDavid Wei int i; 6363762ec05SDavid Wei 6373762ec05SDavid Wei ns->rq = kvcalloc(dev->num_rx_queues, sizeof(*ns->rq), 6383762ec05SDavid Wei GFP_KERNEL_ACCOUNT | __GFP_RETRY_MAYFAIL); 6393762ec05SDavid Wei if (!ns->rq) 6403762ec05SDavid Wei return -ENOMEM; 6413762ec05SDavid Wei 6423762ec05SDavid Wei for (i = 0; i < dev->num_rx_queues; i++) 6433762ec05SDavid Wei skb_queue_head_init(&ns->rq[i].skb_queue); 6443762ec05SDavid Wei 6453762ec05SDavid Wei return 0; 6463762ec05SDavid Wei } 6473762ec05SDavid Wei 6483762ec05SDavid Wei static void nsim_queue_free(struct netdevsim *ns) 6493762ec05SDavid Wei { 6503762ec05SDavid Wei struct net_device *dev = ns->netdev; 6513762ec05SDavid Wei int i; 6523762ec05SDavid Wei 6533762ec05SDavid Wei for (i = 0; i < dev->num_rx_queues; i++) 6543762ec05SDavid Wei skb_queue_purge_reason(&ns->rq[i].skb_queue, 6553762ec05SDavid Wei SKB_DROP_REASON_QUEUE_PURGE); 6563762ec05SDavid Wei 6573762ec05SDavid Wei kvfree(ns->rq); 6583762ec05SDavid Wei ns->rq = NULL; 6593762ec05SDavid Wei } 6603762ec05SDavid Wei 66192ba1f29SDmytro Linkin static int nsim_init_netdevsim(struct netdevsim *ns) 66292ba1f29SDmytro Linkin { 663b63e78fcSVladimir Oltean struct mock_phc *phc; 66492ba1f29SDmytro Linkin int err; 66592ba1f29SDmytro Linkin 666b63e78fcSVladimir Oltean phc = mock_phc_create(&ns->nsim_bus_dev->dev); 667b63e78fcSVladimir Oltean if (IS_ERR(phc)) 668b63e78fcSVladimir Oltean return PTR_ERR(phc); 669b63e78fcSVladimir Oltean 670b63e78fcSVladimir Oltean ns->phc = phc; 67192ba1f29SDmytro Linkin ns->netdev->netdev_ops = &nsim_netdev_ops; 672f216306bSJakub Kicinski ns->netdev->stat_ops = &nsim_stat_ops; 67392ba1f29SDmytro Linkin 67492ba1f29SDmytro Linkin err = nsim_udp_tunnels_info_create(ns->nsim_dev, ns->netdev); 67592ba1f29SDmytro Linkin if (err) 676b63e78fcSVladimir Oltean goto err_phc_destroy; 67792ba1f29SDmytro Linkin 67892ba1f29SDmytro Linkin rtnl_lock(); 6793762ec05SDavid Wei err = nsim_queue_init(ns); 68092ba1f29SDmytro Linkin if (err) 68192ba1f29SDmytro Linkin goto err_utn_destroy; 68292ba1f29SDmytro Linkin 6833762ec05SDavid Wei err = nsim_bpf_init(ns); 6843762ec05SDavid Wei if (err) 6853762ec05SDavid Wei goto err_rq_destroy; 6863762ec05SDavid Wei 68702b34d03SSabrina Dubroca nsim_macsec_init(ns); 68892ba1f29SDmytro Linkin nsim_ipsec_init(ns); 68992ba1f29SDmytro Linkin 69092ba1f29SDmytro Linkin err = register_netdevice(ns->netdev); 69192ba1f29SDmytro Linkin if (err) 69292ba1f29SDmytro Linkin goto err_ipsec_teardown; 69392ba1f29SDmytro Linkin rtnl_unlock(); 69492ba1f29SDmytro Linkin return 0; 69592ba1f29SDmytro Linkin 69692ba1f29SDmytro Linkin err_ipsec_teardown: 69792ba1f29SDmytro Linkin nsim_ipsec_teardown(ns); 69802b34d03SSabrina Dubroca nsim_macsec_teardown(ns); 69992ba1f29SDmytro Linkin nsim_bpf_uninit(ns); 7003762ec05SDavid Wei err_rq_destroy: 7013762ec05SDavid Wei nsim_queue_free(ns); 70292ba1f29SDmytro Linkin err_utn_destroy: 70392ba1f29SDmytro Linkin rtnl_unlock(); 70492ba1f29SDmytro Linkin nsim_udp_tunnels_info_destroy(ns->netdev); 705b63e78fcSVladimir Oltean err_phc_destroy: 706b63e78fcSVladimir Oltean mock_phc_destroy(ns->phc); 70792ba1f29SDmytro Linkin return err; 70892ba1f29SDmytro Linkin } 70992ba1f29SDmytro Linkin 71092ba1f29SDmytro Linkin static int nsim_init_netdevsim_vf(struct netdevsim *ns) 71192ba1f29SDmytro Linkin { 71292ba1f29SDmytro Linkin int err; 71392ba1f29SDmytro Linkin 71492ba1f29SDmytro Linkin ns->netdev->netdev_ops = &nsim_vf_netdev_ops; 71592ba1f29SDmytro Linkin rtnl_lock(); 71692ba1f29SDmytro Linkin err = register_netdevice(ns->netdev); 71792ba1f29SDmytro Linkin rtnl_unlock(); 71892ba1f29SDmytro Linkin return err; 71992ba1f29SDmytro Linkin } 72092ba1f29SDmytro Linkin 721ea937f77SJakub Kicinski static void nsim_exit_netdevsim(struct netdevsim *ns) 722ea937f77SJakub Kicinski { 723ea937f77SJakub Kicinski nsim_udp_tunnels_info_destroy(ns->netdev); 724ea937f77SJakub Kicinski mock_phc_destroy(ns->phc); 725ea937f77SJakub Kicinski } 726ea937f77SJakub Kicinski 727e05b2d14SJiri Pirko struct netdevsim * 728e05b2d14SJiri Pirko nsim_create(struct nsim_dev *nsim_dev, struct nsim_dev_port *nsim_dev_port) 72983c9e13aSJakub Kicinski { 730e05b2d14SJiri Pirko struct net_device *dev; 731e05b2d14SJiri Pirko struct netdevsim *ns; 732af9095f0SJiri Pirko int err; 733eeeaaf18SJakub Kicinski 734d4861fc6SPeilin Ye dev = alloc_netdev_mq(sizeof(*ns), "eth%d", NET_NAME_UNKNOWN, nsim_setup, 735d4861fc6SPeilin Ye nsim_dev->nsim_bus_dev->num_queues); 736e05b2d14SJiri Pirko if (!dev) 737e05b2d14SJiri Pirko return ERR_PTR(-ENOMEM); 738e05b2d14SJiri Pirko 73990d29913SJiri Pirko dev_net_set(dev, nsim_dev_net(nsim_dev)); 740e05b2d14SJiri Pirko ns = netdev_priv(dev); 7418320d145SJiri Pirko ns->netdev = dev; 742863a42b2SHillf Danton u64_stats_init(&ns->syncp); 743e05b2d14SJiri Pirko ns->nsim_dev = nsim_dev; 744e05b2d14SJiri Pirko ns->nsim_dev_port = nsim_dev_port; 745e05b2d14SJiri Pirko ns->nsim_bus_dev = nsim_dev->nsim_bus_dev; 74640e4fe4cSJiri Pirko SET_NETDEV_DEV(dev, &ns->nsim_bus_dev->dev); 747ac73d4bfSJiri Pirko SET_NETDEV_DEVLINK_PORT(dev, &nsim_dev_port->devlink_port); 748ff1f7c17SJakub Kicinski nsim_ethtool_init(ns); 74992ba1f29SDmytro Linkin if (nsim_dev_port_is_pf(nsim_dev_port)) 75092ba1f29SDmytro Linkin err = nsim_init_netdevsim(ns); 75192ba1f29SDmytro Linkin else 75292ba1f29SDmytro Linkin err = nsim_init_netdevsim_vf(ns); 753424be63aSJakub Kicinski if (err) 754424be63aSJakub Kicinski goto err_free_netdev; 7551580cbcbSJakub Kicinski 7561580cbcbSJakub Kicinski ns->pp_dfs = debugfs_create_file("pp_hold", 0600, nsim_dev_port->ddir, 7571580cbcbSJakub Kicinski ns, &nsim_pp_hold_fops); 7581580cbcbSJakub Kicinski 759e05b2d14SJiri Pirko return ns; 760e05b2d14SJiri Pirko 761e05b2d14SJiri Pirko err_free_netdev: 762e05b2d14SJiri Pirko free_netdev(dev); 763e05b2d14SJiri Pirko return ERR_PTR(err); 764e05b2d14SJiri Pirko } 765e05b2d14SJiri Pirko 766e05b2d14SJiri Pirko void nsim_destroy(struct netdevsim *ns) 767e05b2d14SJiri Pirko { 768e05b2d14SJiri Pirko struct net_device *dev = ns->netdev; 769f532957dSDavid Wei struct netdevsim *peer; 770e05b2d14SJiri Pirko 7711580cbcbSJakub Kicinski debugfs_remove(ns->pp_dfs); 7721580cbcbSJakub Kicinski 773e05b2d14SJiri Pirko rtnl_lock(); 774f532957dSDavid Wei peer = rtnl_dereference(ns->peer); 775f532957dSDavid Wei if (peer) 776f532957dSDavid Wei RCU_INIT_POINTER(peer->peer, NULL); 777f532957dSDavid Wei RCU_INIT_POINTER(ns->peer, NULL); 778e05b2d14SJiri Pirko unregister_netdevice(dev); 77992ba1f29SDmytro Linkin if (nsim_dev_port_is_pf(ns->nsim_dev_port)) { 78002b34d03SSabrina Dubroca nsim_macsec_teardown(ns); 781e05b2d14SJiri Pirko nsim_ipsec_teardown(ns); 782e05b2d14SJiri Pirko nsim_bpf_uninit(ns); 7833762ec05SDavid Wei nsim_queue_free(ns); 78492ba1f29SDmytro Linkin } 785e05b2d14SJiri Pirko rtnl_unlock(); 78692ba1f29SDmytro Linkin if (nsim_dev_port_is_pf(ns->nsim_dev_port)) 787ea937f77SJakub Kicinski nsim_exit_netdevsim(ns); 7881580cbcbSJakub Kicinski 7891580cbcbSJakub Kicinski /* Put this intentionally late to exercise the orphaning path */ 7901580cbcbSJakub Kicinski if (ns->page) { 7911580cbcbSJakub Kicinski page_pool_put_full_page(ns->page->pp, ns->page, false); 7921580cbcbSJakub Kicinski ns->page = NULL; 7931580cbcbSJakub Kicinski } 7941580cbcbSJakub Kicinski 795e05b2d14SJiri Pirko free_netdev(dev); 796e05b2d14SJiri Pirko } 797e05b2d14SJiri Pirko 798f532957dSDavid Wei bool netdev_is_nsim(struct net_device *dev) 799f532957dSDavid Wei { 800f532957dSDavid Wei return dev->netdev_ops == &nsim_netdev_ops; 801f532957dSDavid Wei } 802f532957dSDavid Wei 803e05b2d14SJiri Pirko static int nsim_validate(struct nlattr *tb[], struct nlattr *data[], 804e05b2d14SJiri Pirko struct netlink_ext_ack *extack) 805e05b2d14SJiri Pirko { 806d4861fc6SPeilin Ye NL_SET_ERR_MSG_MOD(extack, 807d4861fc6SPeilin Ye "Please use: echo \"[ID] [PORT_COUNT] [NUM_QUEUES]\" > /sys/bus/netdevsim/new_device"); 808e05b2d14SJiri Pirko return -EOPNOTSUPP; 809eeeaaf18SJakub Kicinski } 810eeeaaf18SJakub Kicinski 81183c9e13aSJakub Kicinski static struct rtnl_link_ops nsim_link_ops __read_mostly = { 81283c9e13aSJakub Kicinski .kind = DRV_NAME, 81383c9e13aSJakub Kicinski .validate = nsim_validate, 81483c9e13aSJakub Kicinski }; 81583c9e13aSJakub Kicinski 81683c9e13aSJakub Kicinski static int __init nsim_module_init(void) 81783c9e13aSJakub Kicinski { 81831d3ad83SJakub Kicinski int err; 81931d3ad83SJakub Kicinski 820d514f41eSJiri Pirko err = nsim_dev_init(); 821af9095f0SJiri Pirko if (err) 822ab1d0cc0SJiri Pirko return err; 823eeeaaf18SJakub Kicinski 824925f5afeSJiri Pirko err = nsim_bus_init(); 82531d3ad83SJakub Kicinski if (err) 826d514f41eSJiri Pirko goto err_dev_exit; 82731d3ad83SJakub Kicinski 828a5facc4cSJiri Pirko err = rtnl_link_register(&nsim_link_ops); 82979579220SJakub Kicinski if (err) 830925f5afeSJiri Pirko goto err_bus_exit; 83179579220SJakub Kicinski 83231d3ad83SJakub Kicinski return 0; 83331d3ad83SJakub Kicinski 834925f5afeSJiri Pirko err_bus_exit: 835925f5afeSJiri Pirko nsim_bus_exit(); 836d514f41eSJiri Pirko err_dev_exit: 837d514f41eSJiri Pirko nsim_dev_exit(); 83831d3ad83SJakub Kicinski return err; 83983c9e13aSJakub Kicinski } 84083c9e13aSJakub Kicinski 84183c9e13aSJakub Kicinski static void __exit nsim_module_exit(void) 84283c9e13aSJakub Kicinski { 84383c9e13aSJakub Kicinski rtnl_link_unregister(&nsim_link_ops); 844925f5afeSJiri Pirko nsim_bus_exit(); 845d514f41eSJiri Pirko nsim_dev_exit(); 84683c9e13aSJakub Kicinski } 84783c9e13aSJakub Kicinski 84883c9e13aSJakub Kicinski module_init(nsim_module_init); 84983c9e13aSJakub Kicinski module_exit(nsim_module_exit); 85083c9e13aSJakub Kicinski MODULE_LICENSE("GPL"); 8511fff1f79SJakub Kicinski MODULE_DESCRIPTION("Simulated networking device for testing"); 85283c9e13aSJakub Kicinski MODULE_ALIAS_RTNL_LINK(DRV_NAME); 853