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; 72915c82f8SJakub Kicinski 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 362*5bc8e8dbSJakub Kicinski static int nsim_create_page_pool(struct page_pool **p, struct napi_struct *napi) 3633762ec05SDavid Wei { 364*5bc8e8dbSJakub Kicinski struct page_pool_params params = { 3653762ec05SDavid Wei .order = 0, 3663762ec05SDavid Wei .pool_size = NSIM_RING_SIZE, 3673762ec05SDavid Wei .nid = NUMA_NO_NODE, 368*5bc8e8dbSJakub Kicinski .dev = &napi->dev->dev, 369*5bc8e8dbSJakub Kicinski .napi = napi, 3703762ec05SDavid Wei .dma_dir = DMA_BIDIRECTIONAL, 371*5bc8e8dbSJakub Kicinski .netdev = napi->dev, 3723762ec05SDavid Wei }; 373*5bc8e8dbSJakub Kicinski struct page_pool *pool; 3743762ec05SDavid Wei 375*5bc8e8dbSJakub Kicinski pool = page_pool_create(¶ms); 376*5bc8e8dbSJakub Kicinski if (IS_ERR(pool)) 377*5bc8e8dbSJakub Kicinski return PTR_ERR(pool); 3783762ec05SDavid Wei 379*5bc8e8dbSJakub Kicinski *p = pool; 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++) { 390915c82f8SJakub Kicinski rq = ns->rq[i]; 3913762ec05SDavid Wei 39200adf88bSJakub Kicinski netif_napi_add_config(dev, &rq->napi, nsim_poll, i); 3933762ec05SDavid Wei } 3943762ec05SDavid Wei 3953762ec05SDavid Wei for (i = 0; i < dev->num_rx_queues; i++) { 396915c82f8SJakub Kicinski rq = ns->rq[i]; 3973762ec05SDavid Wei 398*5bc8e8dbSJakub Kicinski err = nsim_create_page_pool(&rq->page_pool, &rq->napi); 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--) { 407915c82f8SJakub Kicinski page_pool_destroy(ns->rq[i]->page_pool); 408915c82f8SJakub Kicinski ns->rq[i]->page_pool = NULL; 4093762ec05SDavid Wei } 4103762ec05SDavid Wei 4113762ec05SDavid Wei for (i = 0; i < dev->num_rx_queues; i++) 412915c82f8SJakub Kicinski __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++) { 423915c82f8SJakub Kicinski 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++) { 450915c82f8SJakub Kicinski 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++) { 458915c82f8SJakub Kicinski page_pool_destroy(ns->rq[i]->page_pool); 459915c82f8SJakub Kicinski 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 478b3ea4164SPaolo Abeni static int nsim_shaper_set(struct net_shaper_binding *binding, 479b3ea4164SPaolo Abeni const struct net_shaper *shaper, 480b3ea4164SPaolo Abeni struct netlink_ext_ack *extack) 481b3ea4164SPaolo Abeni { 482b3ea4164SPaolo Abeni return 0; 483b3ea4164SPaolo Abeni } 484b3ea4164SPaolo Abeni 485b3ea4164SPaolo Abeni static int nsim_shaper_del(struct net_shaper_binding *binding, 486b3ea4164SPaolo Abeni const struct net_shaper_handle *handle, 487b3ea4164SPaolo Abeni struct netlink_ext_ack *extack) 488b3ea4164SPaolo Abeni { 489b3ea4164SPaolo Abeni return 0; 490b3ea4164SPaolo Abeni } 491b3ea4164SPaolo Abeni 492b3ea4164SPaolo Abeni static int nsim_shaper_group(struct net_shaper_binding *binding, 493b3ea4164SPaolo Abeni int leaves_count, 494b3ea4164SPaolo Abeni const struct net_shaper *leaves, 495b3ea4164SPaolo Abeni const struct net_shaper *root, 496b3ea4164SPaolo Abeni struct netlink_ext_ack *extack) 497b3ea4164SPaolo Abeni { 498b3ea4164SPaolo Abeni return 0; 499b3ea4164SPaolo Abeni } 500b3ea4164SPaolo Abeni 501b3ea4164SPaolo Abeni static void nsim_shaper_cap(struct net_shaper_binding *binding, 502b3ea4164SPaolo Abeni enum net_shaper_scope scope, 503b3ea4164SPaolo Abeni unsigned long *flags) 504b3ea4164SPaolo Abeni { 505b3ea4164SPaolo Abeni *flags = ULONG_MAX; 506b3ea4164SPaolo Abeni } 507b3ea4164SPaolo Abeni 508b3ea4164SPaolo Abeni static const struct net_shaper_ops nsim_shaper_ops = { 509b3ea4164SPaolo Abeni .set = nsim_shaper_set, 510b3ea4164SPaolo Abeni .delete = nsim_shaper_del, 511b3ea4164SPaolo Abeni .group = nsim_shaper_group, 512b3ea4164SPaolo Abeni .capabilities = nsim_shaper_cap, 513b3ea4164SPaolo Abeni }; 514b3ea4164SPaolo Abeni 51583c9e13aSJakub Kicinski static const struct net_device_ops nsim_netdev_ops = { 51683c9e13aSJakub Kicinski .ndo_start_xmit = nsim_start_xmit, 51783c9e13aSJakub Kicinski .ndo_set_rx_mode = nsim_set_rx_mode, 51883c9e13aSJakub Kicinski .ndo_set_mac_address = eth_mac_addr, 51983c9e13aSJakub Kicinski .ndo_validate_addr = eth_validate_addr, 52031d3ad83SJakub Kicinski .ndo_change_mtu = nsim_change_mtu, 52183c9e13aSJakub Kicinski .ndo_get_stats64 = nsim_get_stats64, 52279579220SJakub Kicinski .ndo_set_vf_mac = nsim_set_vf_mac, 52379579220SJakub Kicinski .ndo_set_vf_vlan = nsim_set_vf_vlan, 52479579220SJakub Kicinski .ndo_set_vf_rate = nsim_set_vf_rate, 52579579220SJakub Kicinski .ndo_set_vf_spoofchk = nsim_set_vf_spoofchk, 52679579220SJakub Kicinski .ndo_set_vf_trust = nsim_set_vf_trust, 52779579220SJakub Kicinski .ndo_get_vf_config = nsim_get_vf_config, 52879579220SJakub Kicinski .ndo_set_vf_link_state = nsim_set_vf_link_state, 52979579220SJakub Kicinski .ndo_set_vf_rss_query_en = nsim_set_vf_rss_query_en, 53031d3ad83SJakub Kicinski .ndo_setup_tc = nsim_setup_tc, 53131d3ad83SJakub Kicinski .ndo_set_features = nsim_set_features, 5328debcf58SDavid Wei .ndo_get_iflink = nsim_get_iflink, 53331d3ad83SJakub Kicinski .ndo_bpf = nsim_bpf, 5341580cbcbSJakub Kicinski .ndo_open = nsim_open, 5351580cbcbSJakub Kicinski .ndo_stop = nsim_stop, 536b3ea4164SPaolo Abeni .net_shaper_ops = &nsim_shaper_ops, 53783c9e13aSJakub Kicinski }; 53883c9e13aSJakub Kicinski 53992ba1f29SDmytro Linkin static const struct net_device_ops nsim_vf_netdev_ops = { 54092ba1f29SDmytro Linkin .ndo_start_xmit = nsim_start_xmit, 54192ba1f29SDmytro Linkin .ndo_set_rx_mode = nsim_set_rx_mode, 54292ba1f29SDmytro Linkin .ndo_set_mac_address = eth_mac_addr, 54392ba1f29SDmytro Linkin .ndo_validate_addr = eth_validate_addr, 54492ba1f29SDmytro Linkin .ndo_change_mtu = nsim_change_mtu, 54592ba1f29SDmytro Linkin .ndo_get_stats64 = nsim_get_stats64, 54692ba1f29SDmytro Linkin .ndo_setup_tc = nsim_setup_tc, 54792ba1f29SDmytro Linkin .ndo_set_features = nsim_set_features, 54892ba1f29SDmytro Linkin }; 54992ba1f29SDmytro Linkin 550f216306bSJakub Kicinski /* We don't have true per-queue stats, yet, so do some random fakery here. 551f216306bSJakub Kicinski * Only report stuff for queue 0. 552f216306bSJakub Kicinski */ 553f216306bSJakub Kicinski static void nsim_get_queue_stats_rx(struct net_device *dev, int idx, 554f216306bSJakub Kicinski struct netdev_queue_stats_rx *stats) 555f216306bSJakub Kicinski { 556f216306bSJakub Kicinski struct rtnl_link_stats64 rtstats = {}; 557f216306bSJakub Kicinski 558f216306bSJakub Kicinski if (!idx) 559f216306bSJakub Kicinski nsim_get_stats64(dev, &rtstats); 560f216306bSJakub Kicinski 561f216306bSJakub Kicinski stats->packets = rtstats.rx_packets - !!rtstats.rx_packets; 562f216306bSJakub Kicinski stats->bytes = rtstats.rx_bytes; 563f216306bSJakub Kicinski } 564f216306bSJakub Kicinski 565f216306bSJakub Kicinski static void nsim_get_queue_stats_tx(struct net_device *dev, int idx, 566f216306bSJakub Kicinski struct netdev_queue_stats_tx *stats) 567f216306bSJakub Kicinski { 568f216306bSJakub Kicinski struct rtnl_link_stats64 rtstats = {}; 569f216306bSJakub Kicinski 570f216306bSJakub Kicinski if (!idx) 571f216306bSJakub Kicinski nsim_get_stats64(dev, &rtstats); 572f216306bSJakub Kicinski 573f216306bSJakub Kicinski stats->packets = rtstats.tx_packets - !!rtstats.tx_packets; 574f216306bSJakub Kicinski stats->bytes = rtstats.tx_bytes; 575f216306bSJakub Kicinski } 576f216306bSJakub Kicinski 577f216306bSJakub Kicinski static void nsim_get_base_stats(struct net_device *dev, 578f216306bSJakub Kicinski struct netdev_queue_stats_rx *rx, 579f216306bSJakub Kicinski struct netdev_queue_stats_tx *tx) 580f216306bSJakub Kicinski { 581f216306bSJakub Kicinski struct rtnl_link_stats64 rtstats = {}; 582f216306bSJakub Kicinski 583f216306bSJakub Kicinski nsim_get_stats64(dev, &rtstats); 584f216306bSJakub Kicinski 585f216306bSJakub Kicinski rx->packets = !!rtstats.rx_packets; 586f216306bSJakub Kicinski rx->bytes = 0; 587f216306bSJakub Kicinski tx->packets = !!rtstats.tx_packets; 588f216306bSJakub Kicinski tx->bytes = 0; 589f216306bSJakub Kicinski } 590f216306bSJakub Kicinski 591f216306bSJakub Kicinski static const struct netdev_stat_ops nsim_stat_ops = { 592f216306bSJakub Kicinski .get_queue_stats_tx = nsim_get_queue_stats_tx, 593f216306bSJakub Kicinski .get_queue_stats_rx = nsim_get_queue_stats_rx, 594f216306bSJakub Kicinski .get_base_stats = nsim_get_base_stats, 595f216306bSJakub Kicinski }; 596f216306bSJakub Kicinski 597a565dd04SJakub Kicinski static struct nsim_rq *nsim_queue_alloc(void) 598a565dd04SJakub Kicinski { 599a565dd04SJakub Kicinski struct nsim_rq *rq; 600a565dd04SJakub Kicinski 601a565dd04SJakub Kicinski rq = kzalloc(sizeof(*rq), GFP_KERNEL_ACCOUNT); 602a565dd04SJakub Kicinski if (!rq) 603a565dd04SJakub Kicinski return NULL; 604a565dd04SJakub Kicinski 605a565dd04SJakub Kicinski skb_queue_head_init(&rq->skb_queue); 606a565dd04SJakub Kicinski return rq; 607a565dd04SJakub Kicinski } 608a565dd04SJakub Kicinski 609a565dd04SJakub Kicinski static void nsim_queue_free(struct nsim_rq *rq) 610a565dd04SJakub Kicinski { 611a565dd04SJakub Kicinski skb_queue_purge_reason(&rq->skb_queue, SKB_DROP_REASON_QUEUE_PURGE); 612a565dd04SJakub Kicinski kfree(rq); 613a565dd04SJakub Kicinski } 614a565dd04SJakub Kicinski 615*5bc8e8dbSJakub Kicinski /* Queue reset mode is controlled by ns->rq_reset_mode. 616*5bc8e8dbSJakub Kicinski * - normal - new NAPI new pool (old NAPI enabled when new added) 617*5bc8e8dbSJakub Kicinski * - mode 1 - allocate new pool (NAPI is only disabled / enabled) 618*5bc8e8dbSJakub Kicinski * - mode 2 - new NAPI new pool (old NAPI removed before new added) 619*5bc8e8dbSJakub Kicinski * - mode 3 - new NAPI new pool (old NAPI disabled when new added) 620*5bc8e8dbSJakub Kicinski */ 621*5bc8e8dbSJakub Kicinski struct nsim_queue_mem { 622*5bc8e8dbSJakub Kicinski struct nsim_rq *rq; 623*5bc8e8dbSJakub Kicinski struct page_pool *pp; 624*5bc8e8dbSJakub Kicinski }; 625*5bc8e8dbSJakub Kicinski 626*5bc8e8dbSJakub Kicinski static int 627*5bc8e8dbSJakub Kicinski nsim_queue_mem_alloc(struct net_device *dev, void *per_queue_mem, int idx) 628*5bc8e8dbSJakub Kicinski { 629*5bc8e8dbSJakub Kicinski struct nsim_queue_mem *qmem = per_queue_mem; 630*5bc8e8dbSJakub Kicinski struct netdevsim *ns = netdev_priv(dev); 631*5bc8e8dbSJakub Kicinski int err; 632*5bc8e8dbSJakub Kicinski 633*5bc8e8dbSJakub Kicinski if (ns->rq_reset_mode > 3) 634*5bc8e8dbSJakub Kicinski return -EINVAL; 635*5bc8e8dbSJakub Kicinski 636*5bc8e8dbSJakub Kicinski if (ns->rq_reset_mode == 1) 637*5bc8e8dbSJakub Kicinski return nsim_create_page_pool(&qmem->pp, &ns->rq[idx]->napi); 638*5bc8e8dbSJakub Kicinski 639*5bc8e8dbSJakub Kicinski qmem->rq = nsim_queue_alloc(); 640*5bc8e8dbSJakub Kicinski if (!qmem->rq) 641*5bc8e8dbSJakub Kicinski return -ENOMEM; 642*5bc8e8dbSJakub Kicinski 643*5bc8e8dbSJakub Kicinski err = nsim_create_page_pool(&qmem->rq->page_pool, &qmem->rq->napi); 644*5bc8e8dbSJakub Kicinski if (err) 645*5bc8e8dbSJakub Kicinski goto err_free; 646*5bc8e8dbSJakub Kicinski 647*5bc8e8dbSJakub Kicinski if (!ns->rq_reset_mode) 648*5bc8e8dbSJakub Kicinski netif_napi_add_config(dev, &qmem->rq->napi, nsim_poll, idx); 649*5bc8e8dbSJakub Kicinski 650*5bc8e8dbSJakub Kicinski return 0; 651*5bc8e8dbSJakub Kicinski 652*5bc8e8dbSJakub Kicinski err_free: 653*5bc8e8dbSJakub Kicinski nsim_queue_free(qmem->rq); 654*5bc8e8dbSJakub Kicinski return err; 655*5bc8e8dbSJakub Kicinski } 656*5bc8e8dbSJakub Kicinski 657*5bc8e8dbSJakub Kicinski static void nsim_queue_mem_free(struct net_device *dev, void *per_queue_mem) 658*5bc8e8dbSJakub Kicinski { 659*5bc8e8dbSJakub Kicinski struct nsim_queue_mem *qmem = per_queue_mem; 660*5bc8e8dbSJakub Kicinski struct netdevsim *ns = netdev_priv(dev); 661*5bc8e8dbSJakub Kicinski 662*5bc8e8dbSJakub Kicinski page_pool_destroy(qmem->pp); 663*5bc8e8dbSJakub Kicinski if (qmem->rq) { 664*5bc8e8dbSJakub Kicinski if (!ns->rq_reset_mode) 665*5bc8e8dbSJakub Kicinski netif_napi_del(&qmem->rq->napi); 666*5bc8e8dbSJakub Kicinski page_pool_destroy(qmem->rq->page_pool); 667*5bc8e8dbSJakub Kicinski nsim_queue_free(qmem->rq); 668*5bc8e8dbSJakub Kicinski } 669*5bc8e8dbSJakub Kicinski } 670*5bc8e8dbSJakub Kicinski 671*5bc8e8dbSJakub Kicinski static int 672*5bc8e8dbSJakub Kicinski nsim_queue_start(struct net_device *dev, void *per_queue_mem, int idx) 673*5bc8e8dbSJakub Kicinski { 674*5bc8e8dbSJakub Kicinski struct nsim_queue_mem *qmem = per_queue_mem; 675*5bc8e8dbSJakub Kicinski struct netdevsim *ns = netdev_priv(dev); 676*5bc8e8dbSJakub Kicinski 677*5bc8e8dbSJakub Kicinski if (ns->rq_reset_mode == 1) { 678*5bc8e8dbSJakub Kicinski ns->rq[idx]->page_pool = qmem->pp; 679*5bc8e8dbSJakub Kicinski napi_enable(&ns->rq[idx]->napi); 680*5bc8e8dbSJakub Kicinski return 0; 681*5bc8e8dbSJakub Kicinski } 682*5bc8e8dbSJakub Kicinski 683*5bc8e8dbSJakub Kicinski /* netif_napi_add()/_del() should normally be called from alloc/free, 684*5bc8e8dbSJakub Kicinski * here we want to test various call orders. 685*5bc8e8dbSJakub Kicinski */ 686*5bc8e8dbSJakub Kicinski if (ns->rq_reset_mode == 2) { 687*5bc8e8dbSJakub Kicinski netif_napi_del(&ns->rq[idx]->napi); 688*5bc8e8dbSJakub Kicinski netif_napi_add_config(dev, &qmem->rq->napi, nsim_poll, idx); 689*5bc8e8dbSJakub Kicinski } else if (ns->rq_reset_mode == 3) { 690*5bc8e8dbSJakub Kicinski netif_napi_add_config(dev, &qmem->rq->napi, nsim_poll, idx); 691*5bc8e8dbSJakub Kicinski netif_napi_del(&ns->rq[idx]->napi); 692*5bc8e8dbSJakub Kicinski } 693*5bc8e8dbSJakub Kicinski 694*5bc8e8dbSJakub Kicinski ns->rq[idx] = qmem->rq; 695*5bc8e8dbSJakub Kicinski napi_enable(&ns->rq[idx]->napi); 696*5bc8e8dbSJakub Kicinski 697*5bc8e8dbSJakub Kicinski return 0; 698*5bc8e8dbSJakub Kicinski } 699*5bc8e8dbSJakub Kicinski 700*5bc8e8dbSJakub Kicinski static int nsim_queue_stop(struct net_device *dev, void *per_queue_mem, int idx) 701*5bc8e8dbSJakub Kicinski { 702*5bc8e8dbSJakub Kicinski struct nsim_queue_mem *qmem = per_queue_mem; 703*5bc8e8dbSJakub Kicinski struct netdevsim *ns = netdev_priv(dev); 704*5bc8e8dbSJakub Kicinski 705*5bc8e8dbSJakub Kicinski napi_disable(&ns->rq[idx]->napi); 706*5bc8e8dbSJakub Kicinski 707*5bc8e8dbSJakub Kicinski if (ns->rq_reset_mode == 1) { 708*5bc8e8dbSJakub Kicinski qmem->pp = ns->rq[idx]->page_pool; 709*5bc8e8dbSJakub Kicinski page_pool_disable_direct_recycling(qmem->pp); 710*5bc8e8dbSJakub Kicinski } else { 711*5bc8e8dbSJakub Kicinski qmem->rq = ns->rq[idx]; 712*5bc8e8dbSJakub Kicinski } 713*5bc8e8dbSJakub Kicinski 714*5bc8e8dbSJakub Kicinski return 0; 715*5bc8e8dbSJakub Kicinski } 716*5bc8e8dbSJakub Kicinski 717*5bc8e8dbSJakub Kicinski static const struct netdev_queue_mgmt_ops nsim_queue_mgmt_ops = { 718*5bc8e8dbSJakub Kicinski .ndo_queue_mem_size = sizeof(struct nsim_queue_mem), 719*5bc8e8dbSJakub Kicinski .ndo_queue_mem_alloc = nsim_queue_mem_alloc, 720*5bc8e8dbSJakub Kicinski .ndo_queue_mem_free = nsim_queue_mem_free, 721*5bc8e8dbSJakub Kicinski .ndo_queue_start = nsim_queue_start, 722*5bc8e8dbSJakub Kicinski .ndo_queue_stop = nsim_queue_stop, 723*5bc8e8dbSJakub Kicinski }; 724*5bc8e8dbSJakub Kicinski 7251580cbcbSJakub Kicinski static ssize_t 7261580cbcbSJakub Kicinski nsim_pp_hold_read(struct file *file, char __user *data, 7271580cbcbSJakub Kicinski size_t count, loff_t *ppos) 7281580cbcbSJakub Kicinski { 7291580cbcbSJakub Kicinski struct netdevsim *ns = file->private_data; 7301580cbcbSJakub Kicinski char buf[3] = "n\n"; 7311580cbcbSJakub Kicinski 7321580cbcbSJakub Kicinski if (ns->page) 7331580cbcbSJakub Kicinski buf[0] = 'y'; 7341580cbcbSJakub Kicinski 7351580cbcbSJakub Kicinski return simple_read_from_buffer(data, count, ppos, buf, 2); 7361580cbcbSJakub Kicinski } 7371580cbcbSJakub Kicinski 7381580cbcbSJakub Kicinski static ssize_t 7391580cbcbSJakub Kicinski nsim_pp_hold_write(struct file *file, const char __user *data, 7401580cbcbSJakub Kicinski size_t count, loff_t *ppos) 7411580cbcbSJakub Kicinski { 7421580cbcbSJakub Kicinski struct netdevsim *ns = file->private_data; 7431580cbcbSJakub Kicinski ssize_t ret; 7441580cbcbSJakub Kicinski bool val; 7451580cbcbSJakub Kicinski 7461580cbcbSJakub Kicinski ret = kstrtobool_from_user(data, count, &val); 7471580cbcbSJakub Kicinski if (ret) 7481580cbcbSJakub Kicinski return ret; 7491580cbcbSJakub Kicinski 7501580cbcbSJakub Kicinski rtnl_lock(); 7511580cbcbSJakub Kicinski ret = count; 7521580cbcbSJakub Kicinski if (val == !!ns->page) 7531580cbcbSJakub Kicinski goto exit; 7541580cbcbSJakub Kicinski 7551580cbcbSJakub Kicinski if (!netif_running(ns->netdev) && val) { 7561580cbcbSJakub Kicinski ret = -ENETDOWN; 7571580cbcbSJakub Kicinski } else if (val) { 758915c82f8SJakub Kicinski ns->page = page_pool_dev_alloc_pages(ns->rq[0]->page_pool); 7591580cbcbSJakub Kicinski if (!ns->page) 7601580cbcbSJakub Kicinski ret = -ENOMEM; 7611580cbcbSJakub Kicinski } else { 7621580cbcbSJakub Kicinski page_pool_put_full_page(ns->page->pp, ns->page, false); 7631580cbcbSJakub Kicinski ns->page = NULL; 7641580cbcbSJakub Kicinski } 7651580cbcbSJakub Kicinski 7661580cbcbSJakub Kicinski exit: 767b9b8301dSEric Dumazet rtnl_unlock(); 768b9b8301dSEric Dumazet return ret; 7691580cbcbSJakub Kicinski } 7701580cbcbSJakub Kicinski 7711580cbcbSJakub Kicinski static const struct file_operations nsim_pp_hold_fops = { 7721580cbcbSJakub Kicinski .open = simple_open, 7731580cbcbSJakub Kicinski .read = nsim_pp_hold_read, 7741580cbcbSJakub Kicinski .write = nsim_pp_hold_write, 7751580cbcbSJakub Kicinski .llseek = generic_file_llseek, 7761580cbcbSJakub Kicinski .owner = THIS_MODULE, 7771580cbcbSJakub Kicinski }; 7781580cbcbSJakub Kicinski 77983c9e13aSJakub Kicinski static void nsim_setup(struct net_device *dev) 78083c9e13aSJakub Kicinski { 78183c9e13aSJakub Kicinski ether_setup(dev); 78283c9e13aSJakub Kicinski eth_hw_addr_random(dev); 78383c9e13aSJakub Kicinski 78483c9e13aSJakub Kicinski dev->tx_queue_len = 0; 78583c9e13aSJakub Kicinski dev->flags &= ~IFF_MULTICAST; 78683c9e13aSJakub Kicinski dev->priv_flags |= IFF_LIVE_ADDR_CHANGE | 78783c9e13aSJakub Kicinski IFF_NO_QUEUE; 78883c9e13aSJakub Kicinski dev->features |= NETIF_F_HIGHDMA | 78983c9e13aSJakub Kicinski NETIF_F_SG | 79083c9e13aSJakub Kicinski NETIF_F_FRAGLIST | 79183c9e13aSJakub Kicinski NETIF_F_HW_CSUM | 79283c9e13aSJakub Kicinski NETIF_F_TSO; 793494bd83bSSabrina Dubroca dev->hw_features |= NETIF_F_HW_TC | 794494bd83bSSabrina Dubroca NETIF_F_SG | 795494bd83bSSabrina Dubroca NETIF_F_FRAGLIST | 796494bd83bSSabrina Dubroca NETIF_F_HW_CSUM | 797494bd83bSSabrina Dubroca NETIF_F_TSO; 79883c9e13aSJakub Kicinski dev->max_mtu = ETH_MAX_MTU; 79966c0e13aSMarek Majtyka dev->xdp_features = NETDEV_XDP_ACT_HW_OFFLOAD; 80083c9e13aSJakub Kicinski } 80183c9e13aSJakub Kicinski 8023762ec05SDavid Wei static int nsim_queue_init(struct netdevsim *ns) 8033762ec05SDavid Wei { 8043762ec05SDavid Wei struct net_device *dev = ns->netdev; 8053762ec05SDavid Wei int i; 8063762ec05SDavid Wei 807915c82f8SJakub Kicinski ns->rq = kcalloc(dev->num_rx_queues, sizeof(*ns->rq), 808915c82f8SJakub Kicinski GFP_KERNEL_ACCOUNT); 8093762ec05SDavid Wei if (!ns->rq) 8103762ec05SDavid Wei return -ENOMEM; 8113762ec05SDavid Wei 812915c82f8SJakub Kicinski for (i = 0; i < dev->num_rx_queues; i++) { 813a565dd04SJakub Kicinski ns->rq[i] = nsim_queue_alloc(); 814915c82f8SJakub Kicinski if (!ns->rq[i]) 815915c82f8SJakub Kicinski goto err_free_prev; 816915c82f8SJakub Kicinski } 8173762ec05SDavid Wei 8183762ec05SDavid Wei return 0; 819915c82f8SJakub Kicinski 820915c82f8SJakub Kicinski err_free_prev: 821915c82f8SJakub Kicinski while (i--) 822915c82f8SJakub Kicinski kfree(ns->rq[i]); 823915c82f8SJakub Kicinski kfree(ns->rq); 824915c82f8SJakub Kicinski return -ENOMEM; 8253762ec05SDavid Wei } 8263762ec05SDavid Wei 827a565dd04SJakub Kicinski static void nsim_queue_uninit(struct netdevsim *ns) 8283762ec05SDavid Wei { 8293762ec05SDavid Wei struct net_device *dev = ns->netdev; 8303762ec05SDavid Wei int i; 8313762ec05SDavid Wei 832a565dd04SJakub Kicinski for (i = 0; i < dev->num_rx_queues; i++) 833a565dd04SJakub Kicinski nsim_queue_free(ns->rq[i]); 8343762ec05SDavid Wei 835915c82f8SJakub Kicinski kfree(ns->rq); 8363762ec05SDavid Wei ns->rq = NULL; 8373762ec05SDavid Wei } 8383762ec05SDavid Wei 83992ba1f29SDmytro Linkin static int nsim_init_netdevsim(struct netdevsim *ns) 84092ba1f29SDmytro Linkin { 841b63e78fcSVladimir Oltean struct mock_phc *phc; 84292ba1f29SDmytro Linkin int err; 84392ba1f29SDmytro Linkin 844b63e78fcSVladimir Oltean phc = mock_phc_create(&ns->nsim_bus_dev->dev); 845b63e78fcSVladimir Oltean if (IS_ERR(phc)) 846b63e78fcSVladimir Oltean return PTR_ERR(phc); 847b63e78fcSVladimir Oltean 848b63e78fcSVladimir Oltean ns->phc = phc; 84992ba1f29SDmytro Linkin ns->netdev->netdev_ops = &nsim_netdev_ops; 850f216306bSJakub Kicinski ns->netdev->stat_ops = &nsim_stat_ops; 851*5bc8e8dbSJakub Kicinski ns->netdev->queue_mgmt_ops = &nsim_queue_mgmt_ops; 85292ba1f29SDmytro Linkin 85392ba1f29SDmytro Linkin err = nsim_udp_tunnels_info_create(ns->nsim_dev, ns->netdev); 85492ba1f29SDmytro Linkin if (err) 855b63e78fcSVladimir Oltean goto err_phc_destroy; 85692ba1f29SDmytro Linkin 85792ba1f29SDmytro Linkin rtnl_lock(); 8583762ec05SDavid Wei err = nsim_queue_init(ns); 85992ba1f29SDmytro Linkin if (err) 86092ba1f29SDmytro Linkin goto err_utn_destroy; 86192ba1f29SDmytro Linkin 8623762ec05SDavid Wei err = nsim_bpf_init(ns); 8633762ec05SDavid Wei if (err) 8643762ec05SDavid Wei goto err_rq_destroy; 8653762ec05SDavid Wei 86602b34d03SSabrina Dubroca nsim_macsec_init(ns); 86792ba1f29SDmytro Linkin nsim_ipsec_init(ns); 86892ba1f29SDmytro Linkin 86992ba1f29SDmytro Linkin err = register_netdevice(ns->netdev); 87092ba1f29SDmytro Linkin if (err) 87192ba1f29SDmytro Linkin goto err_ipsec_teardown; 87292ba1f29SDmytro Linkin rtnl_unlock(); 87392ba1f29SDmytro Linkin return 0; 87492ba1f29SDmytro Linkin 87592ba1f29SDmytro Linkin err_ipsec_teardown: 87692ba1f29SDmytro Linkin nsim_ipsec_teardown(ns); 87702b34d03SSabrina Dubroca nsim_macsec_teardown(ns); 87892ba1f29SDmytro Linkin nsim_bpf_uninit(ns); 8793762ec05SDavid Wei err_rq_destroy: 880a565dd04SJakub Kicinski nsim_queue_uninit(ns); 88192ba1f29SDmytro Linkin err_utn_destroy: 88292ba1f29SDmytro Linkin rtnl_unlock(); 88392ba1f29SDmytro Linkin nsim_udp_tunnels_info_destroy(ns->netdev); 884b63e78fcSVladimir Oltean err_phc_destroy: 885b63e78fcSVladimir Oltean mock_phc_destroy(ns->phc); 88692ba1f29SDmytro Linkin return err; 88792ba1f29SDmytro Linkin } 88892ba1f29SDmytro Linkin 88992ba1f29SDmytro Linkin static int nsim_init_netdevsim_vf(struct netdevsim *ns) 89092ba1f29SDmytro Linkin { 89192ba1f29SDmytro Linkin int err; 89292ba1f29SDmytro Linkin 89392ba1f29SDmytro Linkin ns->netdev->netdev_ops = &nsim_vf_netdev_ops; 89492ba1f29SDmytro Linkin rtnl_lock(); 89592ba1f29SDmytro Linkin err = register_netdevice(ns->netdev); 89692ba1f29SDmytro Linkin rtnl_unlock(); 89792ba1f29SDmytro Linkin return err; 89892ba1f29SDmytro Linkin } 89992ba1f29SDmytro Linkin 900ea937f77SJakub Kicinski static void nsim_exit_netdevsim(struct netdevsim *ns) 901ea937f77SJakub Kicinski { 902ea937f77SJakub Kicinski nsim_udp_tunnels_info_destroy(ns->netdev); 903ea937f77SJakub Kicinski mock_phc_destroy(ns->phc); 904ea937f77SJakub Kicinski } 905ea937f77SJakub Kicinski 906e05b2d14SJiri Pirko struct netdevsim * 907e05b2d14SJiri Pirko nsim_create(struct nsim_dev *nsim_dev, struct nsim_dev_port *nsim_dev_port) 90883c9e13aSJakub Kicinski { 909e05b2d14SJiri Pirko struct net_device *dev; 910e05b2d14SJiri Pirko struct netdevsim *ns; 911af9095f0SJiri Pirko int err; 912eeeaaf18SJakub Kicinski 913d4861fc6SPeilin Ye dev = alloc_netdev_mq(sizeof(*ns), "eth%d", NET_NAME_UNKNOWN, nsim_setup, 914d4861fc6SPeilin Ye nsim_dev->nsim_bus_dev->num_queues); 915e05b2d14SJiri Pirko if (!dev) 916e05b2d14SJiri Pirko return ERR_PTR(-ENOMEM); 917e05b2d14SJiri Pirko 91890d29913SJiri Pirko dev_net_set(dev, nsim_dev_net(nsim_dev)); 919e05b2d14SJiri Pirko ns = netdev_priv(dev); 9208320d145SJiri Pirko ns->netdev = dev; 921863a42b2SHillf Danton u64_stats_init(&ns->syncp); 922e05b2d14SJiri Pirko ns->nsim_dev = nsim_dev; 923e05b2d14SJiri Pirko ns->nsim_dev_port = nsim_dev_port; 924e05b2d14SJiri Pirko ns->nsim_bus_dev = nsim_dev->nsim_bus_dev; 92540e4fe4cSJiri Pirko SET_NETDEV_DEV(dev, &ns->nsim_bus_dev->dev); 926ac73d4bfSJiri Pirko SET_NETDEV_DEVLINK_PORT(dev, &nsim_dev_port->devlink_port); 927ff1f7c17SJakub Kicinski nsim_ethtool_init(ns); 92892ba1f29SDmytro Linkin if (nsim_dev_port_is_pf(nsim_dev_port)) 92992ba1f29SDmytro Linkin err = nsim_init_netdevsim(ns); 93092ba1f29SDmytro Linkin else 93192ba1f29SDmytro Linkin err = nsim_init_netdevsim_vf(ns); 932424be63aSJakub Kicinski if (err) 933424be63aSJakub Kicinski goto err_free_netdev; 9341580cbcbSJakub Kicinski 9351580cbcbSJakub Kicinski ns->pp_dfs = debugfs_create_file("pp_hold", 0600, nsim_dev_port->ddir, 9361580cbcbSJakub Kicinski ns, &nsim_pp_hold_fops); 9371580cbcbSJakub Kicinski 938e05b2d14SJiri Pirko return ns; 939e05b2d14SJiri Pirko 940e05b2d14SJiri Pirko err_free_netdev: 941e05b2d14SJiri Pirko free_netdev(dev); 942e05b2d14SJiri Pirko return ERR_PTR(err); 943e05b2d14SJiri Pirko } 944e05b2d14SJiri Pirko 945e05b2d14SJiri Pirko void nsim_destroy(struct netdevsim *ns) 946e05b2d14SJiri Pirko { 947e05b2d14SJiri Pirko struct net_device *dev = ns->netdev; 948f532957dSDavid Wei struct netdevsim *peer; 949e05b2d14SJiri Pirko 9501580cbcbSJakub Kicinski debugfs_remove(ns->pp_dfs); 9511580cbcbSJakub Kicinski 952e05b2d14SJiri Pirko rtnl_lock(); 953f532957dSDavid Wei peer = rtnl_dereference(ns->peer); 954f532957dSDavid Wei if (peer) 955f532957dSDavid Wei RCU_INIT_POINTER(peer->peer, NULL); 956f532957dSDavid Wei RCU_INIT_POINTER(ns->peer, NULL); 957e05b2d14SJiri Pirko unregister_netdevice(dev); 95892ba1f29SDmytro Linkin if (nsim_dev_port_is_pf(ns->nsim_dev_port)) { 95902b34d03SSabrina Dubroca nsim_macsec_teardown(ns); 960e05b2d14SJiri Pirko nsim_ipsec_teardown(ns); 961e05b2d14SJiri Pirko nsim_bpf_uninit(ns); 962a565dd04SJakub Kicinski nsim_queue_uninit(ns); 96392ba1f29SDmytro Linkin } 964e05b2d14SJiri Pirko rtnl_unlock(); 96592ba1f29SDmytro Linkin if (nsim_dev_port_is_pf(ns->nsim_dev_port)) 966ea937f77SJakub Kicinski nsim_exit_netdevsim(ns); 9671580cbcbSJakub Kicinski 9681580cbcbSJakub Kicinski /* Put this intentionally late to exercise the orphaning path */ 9691580cbcbSJakub Kicinski if (ns->page) { 9701580cbcbSJakub Kicinski page_pool_put_full_page(ns->page->pp, ns->page, false); 9711580cbcbSJakub Kicinski ns->page = NULL; 9721580cbcbSJakub Kicinski } 9731580cbcbSJakub Kicinski 974e05b2d14SJiri Pirko free_netdev(dev); 975e05b2d14SJiri Pirko } 976e05b2d14SJiri Pirko 977f532957dSDavid Wei bool netdev_is_nsim(struct net_device *dev) 978f532957dSDavid Wei { 979f532957dSDavid Wei return dev->netdev_ops == &nsim_netdev_ops; 980f532957dSDavid Wei } 981f532957dSDavid Wei 982e05b2d14SJiri Pirko static int nsim_validate(struct nlattr *tb[], struct nlattr *data[], 983e05b2d14SJiri Pirko struct netlink_ext_ack *extack) 984e05b2d14SJiri Pirko { 985d4861fc6SPeilin Ye NL_SET_ERR_MSG_MOD(extack, 986d4861fc6SPeilin Ye "Please use: echo \"[ID] [PORT_COUNT] [NUM_QUEUES]\" > /sys/bus/netdevsim/new_device"); 987e05b2d14SJiri Pirko return -EOPNOTSUPP; 988eeeaaf18SJakub Kicinski } 989eeeaaf18SJakub Kicinski 99083c9e13aSJakub Kicinski static struct rtnl_link_ops nsim_link_ops __read_mostly = { 99183c9e13aSJakub Kicinski .kind = DRV_NAME, 99283c9e13aSJakub Kicinski .validate = nsim_validate, 99383c9e13aSJakub Kicinski }; 99483c9e13aSJakub Kicinski 99583c9e13aSJakub Kicinski static int __init nsim_module_init(void) 99683c9e13aSJakub Kicinski { 99731d3ad83SJakub Kicinski int err; 99831d3ad83SJakub Kicinski 999d514f41eSJiri Pirko err = nsim_dev_init(); 1000af9095f0SJiri Pirko if (err) 1001ab1d0cc0SJiri Pirko return err; 1002eeeaaf18SJakub Kicinski 1003925f5afeSJiri Pirko err = nsim_bus_init(); 100431d3ad83SJakub Kicinski if (err) 1005d514f41eSJiri Pirko goto err_dev_exit; 100631d3ad83SJakub Kicinski 1007a5facc4cSJiri Pirko err = rtnl_link_register(&nsim_link_ops); 100879579220SJakub Kicinski if (err) 1009925f5afeSJiri Pirko goto err_bus_exit; 101079579220SJakub Kicinski 101131d3ad83SJakub Kicinski return 0; 101231d3ad83SJakub Kicinski 1013925f5afeSJiri Pirko err_bus_exit: 1014925f5afeSJiri Pirko nsim_bus_exit(); 1015d514f41eSJiri Pirko err_dev_exit: 1016d514f41eSJiri Pirko nsim_dev_exit(); 101731d3ad83SJakub Kicinski return err; 101883c9e13aSJakub Kicinski } 101983c9e13aSJakub Kicinski 102083c9e13aSJakub Kicinski static void __exit nsim_module_exit(void) 102183c9e13aSJakub Kicinski { 102283c9e13aSJakub Kicinski rtnl_link_unregister(&nsim_link_ops); 1023925f5afeSJiri Pirko nsim_bus_exit(); 1024d514f41eSJiri Pirko nsim_dev_exit(); 102583c9e13aSJakub Kicinski } 102683c9e13aSJakub Kicinski 102783c9e13aSJakub Kicinski module_init(nsim_module_init); 102883c9e13aSJakub Kicinski module_exit(nsim_module_exit); 102983c9e13aSJakub Kicinski MODULE_LICENSE("GPL"); 10301fff1f79SJakub Kicinski MODULE_DESCRIPTION("Simulated networking device for testing"); 103183c9e13aSJakub Kicinski MODULE_ALIAS_RTNL_LINK(DRV_NAME); 1032