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> 2283c9e13aSJakub Kicinski #include <net/netlink.h> 2331d3ad83SJakub Kicinski #include <net/pkt_cls.h> 2483c9e13aSJakub Kicinski #include <net/rtnetlink.h> 2583c9e13aSJakub Kicinski 2683c9e13aSJakub Kicinski #include "netdevsim.h" 2783c9e13aSJakub Kicinski 28f61b6db3SJakub Kicinski static struct dentry *nsim_ddir; 29f61b6db3SJakub Kicinski 30e58df56cSFlorian Fainelli static int nsim_get_port_parent_id(struct net_device *dev, 31e58df56cSFlorian Fainelli struct netdev_phys_item_id *ppid) 325f07655bSJakub Kicinski { 335f07655bSJakub Kicinski struct netdevsim *ns = netdev_priv(dev); 345f07655bSJakub Kicinski 35e58df56cSFlorian Fainelli ppid->id_len = sizeof(ns->sdev->switch_id); 36e58df56cSFlorian Fainelli memcpy(&ppid->id, &ns->sdev->switch_id, ppid->id_len); 375f07655bSJakub Kicinski return 0; 385f07655bSJakub Kicinski } 395f07655bSJakub Kicinski 4031d3ad83SJakub Kicinski static int nsim_init(struct net_device *dev) 4131d3ad83SJakub Kicinski { 4231d3ad83SJakub Kicinski struct netdevsim *ns = netdev_priv(dev); 43af9095f0SJiri Pirko char sdev_link_name[32]; 4431d3ad83SJakub Kicinski int err; 4531d3ad83SJakub Kicinski 4631d3ad83SJakub Kicinski ns->ddir = debugfs_create_dir(netdev_name(dev), nsim_ddir); 479ee1942cSPrashant Bhole if (IS_ERR_OR_NULL(ns->ddir)) 489ee1942cSPrashant Bhole return -ENOMEM; 4931d3ad83SJakub Kicinski 50af9095f0SJiri Pirko sprintf(sdev_link_name, "../../" DRV_NAME "_sdev/%u", 51af9095f0SJiri Pirko ns->sdev->switch_id); 52eeeaaf18SJakub Kicinski debugfs_create_symlink("sdev", ns->ddir, sdev_link_name); 53eeeaaf18SJakub Kicinski 5431d3ad83SJakub Kicinski err = nsim_bpf_init(ns); 5531d3ad83SJakub Kicinski if (err) 56af9095f0SJiri Pirko goto err_debugfs_destroy; 5731d3ad83SJakub Kicinski 587699353dSShannon Nelson nsim_ipsec_init(ns); 597699353dSShannon Nelson 6031d3ad83SJakub Kicinski return 0; 6131d3ad83SJakub Kicinski 6231d3ad83SJakub Kicinski err_debugfs_destroy: 6331d3ad83SJakub Kicinski debugfs_remove_recursive(ns->ddir); 6431d3ad83SJakub Kicinski return err; 6531d3ad83SJakub Kicinski } 6631d3ad83SJakub Kicinski 6731d3ad83SJakub Kicinski static void nsim_uninit(struct net_device *dev) 6831d3ad83SJakub Kicinski { 6931d3ad83SJakub Kicinski struct netdevsim *ns = netdev_priv(dev); 7031d3ad83SJakub Kicinski 717699353dSShannon Nelson nsim_ipsec_teardown(ns); 7231d3ad83SJakub Kicinski debugfs_remove_recursive(ns->ddir); 7331d3ad83SJakub Kicinski nsim_bpf_uninit(ns); 7431d3ad83SJakub Kicinski } 7531d3ad83SJakub Kicinski 7679579220SJakub Kicinski static void nsim_free(struct net_device *dev) 7779579220SJakub Kicinski { 7879579220SJakub Kicinski struct netdevsim *ns = netdev_priv(dev); 7979579220SJakub Kicinski 808fb4bc6fSJiri Pirko nsim_dev_exit(ns); 81*40e4fe4cSJiri Pirko nsim_bus_dev_del(ns->nsim_bus_dev); 8279579220SJakub Kicinski /* netdev and vf state will be freed out of device_release() */ 83af9095f0SJiri Pirko nsim_sdev_put(ns->sdev); 8479579220SJakub Kicinski } 8579579220SJakub Kicinski 8683c9e13aSJakub Kicinski static netdev_tx_t nsim_start_xmit(struct sk_buff *skb, struct net_device *dev) 8783c9e13aSJakub Kicinski { 8883c9e13aSJakub Kicinski struct netdevsim *ns = netdev_priv(dev); 8983c9e13aSJakub Kicinski 907699353dSShannon Nelson if (!nsim_ipsec_tx(ns, skb)) 917699353dSShannon Nelson goto out; 927699353dSShannon Nelson 9383c9e13aSJakub Kicinski u64_stats_update_begin(&ns->syncp); 9483c9e13aSJakub Kicinski ns->tx_packets++; 9583c9e13aSJakub Kicinski ns->tx_bytes += skb->len; 9683c9e13aSJakub Kicinski u64_stats_update_end(&ns->syncp); 9783c9e13aSJakub Kicinski 987699353dSShannon Nelson out: 9983c9e13aSJakub Kicinski dev_kfree_skb(skb); 10083c9e13aSJakub Kicinski 10183c9e13aSJakub Kicinski return NETDEV_TX_OK; 10283c9e13aSJakub Kicinski } 10383c9e13aSJakub Kicinski 10483c9e13aSJakub Kicinski static void nsim_set_rx_mode(struct net_device *dev) 10583c9e13aSJakub Kicinski { 10683c9e13aSJakub Kicinski } 10783c9e13aSJakub Kicinski 10831d3ad83SJakub Kicinski static int nsim_change_mtu(struct net_device *dev, int new_mtu) 10931d3ad83SJakub Kicinski { 11031d3ad83SJakub Kicinski struct netdevsim *ns = netdev_priv(dev); 11131d3ad83SJakub Kicinski 112799e173dSJakub Kicinski if (ns->xdp.prog && new_mtu > NSIM_XDP_MAX_MTU) 11331d3ad83SJakub Kicinski return -EBUSY; 11431d3ad83SJakub Kicinski 11531d3ad83SJakub Kicinski dev->mtu = new_mtu; 11631d3ad83SJakub Kicinski 11731d3ad83SJakub Kicinski return 0; 11831d3ad83SJakub Kicinski } 11931d3ad83SJakub Kicinski 12083c9e13aSJakub Kicinski static void 12183c9e13aSJakub Kicinski nsim_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) 12283c9e13aSJakub Kicinski { 12383c9e13aSJakub Kicinski struct netdevsim *ns = netdev_priv(dev); 12483c9e13aSJakub Kicinski unsigned int start; 12583c9e13aSJakub Kicinski 12683c9e13aSJakub Kicinski do { 12783c9e13aSJakub Kicinski start = u64_stats_fetch_begin(&ns->syncp); 12883c9e13aSJakub Kicinski stats->tx_bytes = ns->tx_bytes; 12983c9e13aSJakub Kicinski stats->tx_packets = ns->tx_packets; 13083c9e13aSJakub Kicinski } while (u64_stats_fetch_retry(&ns->syncp, start)); 13183c9e13aSJakub Kicinski } 13283c9e13aSJakub Kicinski 13331d3ad83SJakub Kicinski static int 13431d3ad83SJakub Kicinski nsim_setup_tc_block_cb(enum tc_setup_type type, void *type_data, void *cb_priv) 13531d3ad83SJakub Kicinski { 13631d3ad83SJakub Kicinski return nsim_bpf_setup_tc_block_cb(type, type_data, cb_priv); 13731d3ad83SJakub Kicinski } 13831d3ad83SJakub Kicinski 13931d3ad83SJakub Kicinski static int 14031d3ad83SJakub Kicinski nsim_setup_tc_block(struct net_device *dev, struct tc_block_offload *f) 14131d3ad83SJakub Kicinski { 14231d3ad83SJakub Kicinski struct netdevsim *ns = netdev_priv(dev); 14331d3ad83SJakub Kicinski 14431d3ad83SJakub Kicinski if (f->binder_type != TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS) 14531d3ad83SJakub Kicinski return -EOPNOTSUPP; 14631d3ad83SJakub Kicinski 14731d3ad83SJakub Kicinski switch (f->command) { 14831d3ad83SJakub Kicinski case TC_BLOCK_BIND: 14931d3ad83SJakub Kicinski return tcf_block_cb_register(f->block, nsim_setup_tc_block_cb, 15060513bd8SJohn Hurley ns, ns, f->extack); 15131d3ad83SJakub Kicinski case TC_BLOCK_UNBIND: 15231d3ad83SJakub Kicinski tcf_block_cb_unregister(f->block, nsim_setup_tc_block_cb, ns); 15331d3ad83SJakub Kicinski return 0; 15431d3ad83SJakub Kicinski default: 15531d3ad83SJakub Kicinski return -EOPNOTSUPP; 15631d3ad83SJakub Kicinski } 15731d3ad83SJakub Kicinski } 15831d3ad83SJakub Kicinski 15979579220SJakub Kicinski static int nsim_set_vf_mac(struct net_device *dev, int vf, u8 *mac) 16079579220SJakub Kicinski { 16179579220SJakub Kicinski struct netdevsim *ns = netdev_priv(dev); 162*40e4fe4cSJiri Pirko struct nsim_bus_dev *nsim_bus_dev = ns->nsim_bus_dev; 16379579220SJakub Kicinski 16479579220SJakub Kicinski /* Only refuse multicast addresses, zero address can mean unset/any. */ 165*40e4fe4cSJiri Pirko if (vf >= nsim_bus_dev->num_vfs || is_multicast_ether_addr(mac)) 16679579220SJakub Kicinski return -EINVAL; 167*40e4fe4cSJiri Pirko memcpy(nsim_bus_dev->vfconfigs[vf].vf_mac, mac, ETH_ALEN); 16879579220SJakub Kicinski 16979579220SJakub Kicinski return 0; 17079579220SJakub Kicinski } 17179579220SJakub Kicinski 17279579220SJakub Kicinski static int nsim_set_vf_vlan(struct net_device *dev, int vf, 17379579220SJakub Kicinski u16 vlan, u8 qos, __be16 vlan_proto) 17479579220SJakub Kicinski { 17579579220SJakub Kicinski struct netdevsim *ns = netdev_priv(dev); 176*40e4fe4cSJiri Pirko struct nsim_bus_dev *nsim_bus_dev = ns->nsim_bus_dev; 17779579220SJakub Kicinski 178*40e4fe4cSJiri Pirko if (vf >= nsim_bus_dev->num_vfs || vlan > 4095 || qos > 7) 17979579220SJakub Kicinski return -EINVAL; 18079579220SJakub Kicinski 181*40e4fe4cSJiri Pirko nsim_bus_dev->vfconfigs[vf].vlan = vlan; 182*40e4fe4cSJiri Pirko nsim_bus_dev->vfconfigs[vf].qos = qos; 183*40e4fe4cSJiri Pirko nsim_bus_dev->vfconfigs[vf].vlan_proto = vlan_proto; 18479579220SJakub Kicinski 18579579220SJakub Kicinski return 0; 18679579220SJakub Kicinski } 18779579220SJakub Kicinski 18879579220SJakub Kicinski static int nsim_set_vf_rate(struct net_device *dev, int vf, int min, int max) 18979579220SJakub Kicinski { 19079579220SJakub Kicinski struct netdevsim *ns = netdev_priv(dev); 191*40e4fe4cSJiri Pirko struct nsim_bus_dev *nsim_bus_dev = ns->nsim_bus_dev; 19279579220SJakub Kicinski 193*40e4fe4cSJiri Pirko if (vf >= nsim_bus_dev->num_vfs) 19479579220SJakub Kicinski return -EINVAL; 19579579220SJakub Kicinski 196*40e4fe4cSJiri Pirko nsim_bus_dev->vfconfigs[vf].min_tx_rate = min; 197*40e4fe4cSJiri Pirko nsim_bus_dev->vfconfigs[vf].max_tx_rate = max; 19879579220SJakub Kicinski 19979579220SJakub Kicinski return 0; 20079579220SJakub Kicinski } 20179579220SJakub Kicinski 20279579220SJakub Kicinski static int nsim_set_vf_spoofchk(struct net_device *dev, int vf, bool val) 20379579220SJakub Kicinski { 20479579220SJakub Kicinski struct netdevsim *ns = netdev_priv(dev); 205*40e4fe4cSJiri Pirko struct nsim_bus_dev *nsim_bus_dev = ns->nsim_bus_dev; 20679579220SJakub Kicinski 207*40e4fe4cSJiri Pirko if (vf >= nsim_bus_dev->num_vfs) 20879579220SJakub Kicinski return -EINVAL; 209*40e4fe4cSJiri Pirko nsim_bus_dev->vfconfigs[vf].spoofchk_enabled = val; 21079579220SJakub Kicinski 21179579220SJakub Kicinski return 0; 21279579220SJakub Kicinski } 21379579220SJakub Kicinski 21479579220SJakub Kicinski static int nsim_set_vf_rss_query_en(struct net_device *dev, int vf, bool val) 21579579220SJakub Kicinski { 21679579220SJakub Kicinski struct netdevsim *ns = netdev_priv(dev); 217*40e4fe4cSJiri Pirko struct nsim_bus_dev *nsim_bus_dev = ns->nsim_bus_dev; 21879579220SJakub Kicinski 219*40e4fe4cSJiri Pirko if (vf >= nsim_bus_dev->num_vfs) 22079579220SJakub Kicinski return -EINVAL; 221*40e4fe4cSJiri Pirko nsim_bus_dev->vfconfigs[vf].rss_query_enabled = val; 22279579220SJakub Kicinski 22379579220SJakub Kicinski return 0; 22479579220SJakub Kicinski } 22579579220SJakub Kicinski 22679579220SJakub Kicinski static int nsim_set_vf_trust(struct net_device *dev, int vf, bool val) 22779579220SJakub Kicinski { 22879579220SJakub Kicinski struct netdevsim *ns = netdev_priv(dev); 229*40e4fe4cSJiri Pirko struct nsim_bus_dev *nsim_bus_dev = ns->nsim_bus_dev; 23079579220SJakub Kicinski 231*40e4fe4cSJiri Pirko if (vf >= nsim_bus_dev->num_vfs) 23279579220SJakub Kicinski return -EINVAL; 233*40e4fe4cSJiri Pirko nsim_bus_dev->vfconfigs[vf].trusted = val; 23479579220SJakub Kicinski 23579579220SJakub Kicinski return 0; 23679579220SJakub Kicinski } 23779579220SJakub Kicinski 23879579220SJakub Kicinski static int 23979579220SJakub Kicinski nsim_get_vf_config(struct net_device *dev, int vf, struct ifla_vf_info *ivi) 24079579220SJakub Kicinski { 24179579220SJakub Kicinski struct netdevsim *ns = netdev_priv(dev); 242*40e4fe4cSJiri Pirko struct nsim_bus_dev *nsim_bus_dev = ns->nsim_bus_dev; 24379579220SJakub Kicinski 244*40e4fe4cSJiri Pirko if (vf >= nsim_bus_dev->num_vfs) 24579579220SJakub Kicinski return -EINVAL; 24679579220SJakub Kicinski 24779579220SJakub Kicinski ivi->vf = vf; 248*40e4fe4cSJiri Pirko ivi->linkstate = nsim_bus_dev->vfconfigs[vf].link_state; 249*40e4fe4cSJiri Pirko ivi->min_tx_rate = nsim_bus_dev->vfconfigs[vf].min_tx_rate; 250*40e4fe4cSJiri Pirko ivi->max_tx_rate = nsim_bus_dev->vfconfigs[vf].max_tx_rate; 251*40e4fe4cSJiri Pirko ivi->vlan = nsim_bus_dev->vfconfigs[vf].vlan; 252*40e4fe4cSJiri Pirko ivi->vlan_proto = nsim_bus_dev->vfconfigs[vf].vlan_proto; 253*40e4fe4cSJiri Pirko ivi->qos = nsim_bus_dev->vfconfigs[vf].qos; 254*40e4fe4cSJiri Pirko memcpy(&ivi->mac, nsim_bus_dev->vfconfigs[vf].vf_mac, ETH_ALEN); 255*40e4fe4cSJiri Pirko ivi->spoofchk = nsim_bus_dev->vfconfigs[vf].spoofchk_enabled; 256*40e4fe4cSJiri Pirko ivi->trusted = nsim_bus_dev->vfconfigs[vf].trusted; 257*40e4fe4cSJiri Pirko ivi->rss_query_en = nsim_bus_dev->vfconfigs[vf].rss_query_enabled; 25879579220SJakub Kicinski 25979579220SJakub Kicinski return 0; 26079579220SJakub Kicinski } 26179579220SJakub Kicinski 26279579220SJakub Kicinski static int nsim_set_vf_link_state(struct net_device *dev, int vf, int state) 26379579220SJakub Kicinski { 26479579220SJakub Kicinski struct netdevsim *ns = netdev_priv(dev); 265*40e4fe4cSJiri Pirko struct nsim_bus_dev *nsim_bus_dev = ns->nsim_bus_dev; 26679579220SJakub Kicinski 267*40e4fe4cSJiri Pirko if (vf >= nsim_bus_dev->num_vfs) 26879579220SJakub Kicinski return -EINVAL; 26979579220SJakub Kicinski 27079579220SJakub Kicinski switch (state) { 27179579220SJakub Kicinski case IFLA_VF_LINK_STATE_AUTO: 27279579220SJakub Kicinski case IFLA_VF_LINK_STATE_ENABLE: 27379579220SJakub Kicinski case IFLA_VF_LINK_STATE_DISABLE: 27479579220SJakub Kicinski break; 27579579220SJakub Kicinski default: 27679579220SJakub Kicinski return -EINVAL; 27779579220SJakub Kicinski } 27879579220SJakub Kicinski 279*40e4fe4cSJiri Pirko nsim_bus_dev->vfconfigs[vf].link_state = state; 28079579220SJakub Kicinski 28179579220SJakub Kicinski return 0; 28279579220SJakub Kicinski } 28379579220SJakub Kicinski 28431d3ad83SJakub Kicinski static int 28531d3ad83SJakub Kicinski nsim_setup_tc(struct net_device *dev, enum tc_setup_type type, void *type_data) 28631d3ad83SJakub Kicinski { 28731d3ad83SJakub Kicinski switch (type) { 28831d3ad83SJakub Kicinski case TC_SETUP_BLOCK: 28931d3ad83SJakub Kicinski return nsim_setup_tc_block(dev, type_data); 29031d3ad83SJakub Kicinski default: 29131d3ad83SJakub Kicinski return -EOPNOTSUPP; 29231d3ad83SJakub Kicinski } 29331d3ad83SJakub Kicinski } 29431d3ad83SJakub Kicinski 29531d3ad83SJakub Kicinski static int 29631d3ad83SJakub Kicinski nsim_set_features(struct net_device *dev, netdev_features_t features) 29731d3ad83SJakub Kicinski { 29831d3ad83SJakub Kicinski struct netdevsim *ns = netdev_priv(dev); 29931d3ad83SJakub Kicinski 30031d3ad83SJakub Kicinski if ((dev->features & NETIF_F_HW_TC) > (features & NETIF_F_HW_TC)) 30131d3ad83SJakub Kicinski return nsim_bpf_disable_tc(ns); 30231d3ad83SJakub Kicinski 30331d3ad83SJakub Kicinski return 0; 30431d3ad83SJakub Kicinski } 30531d3ad83SJakub Kicinski 30683c9e13aSJakub Kicinski static const struct net_device_ops nsim_netdev_ops = { 30731d3ad83SJakub Kicinski .ndo_init = nsim_init, 30831d3ad83SJakub Kicinski .ndo_uninit = nsim_uninit, 30983c9e13aSJakub Kicinski .ndo_start_xmit = nsim_start_xmit, 31083c9e13aSJakub Kicinski .ndo_set_rx_mode = nsim_set_rx_mode, 31183c9e13aSJakub Kicinski .ndo_set_mac_address = eth_mac_addr, 31283c9e13aSJakub Kicinski .ndo_validate_addr = eth_validate_addr, 31331d3ad83SJakub Kicinski .ndo_change_mtu = nsim_change_mtu, 31483c9e13aSJakub Kicinski .ndo_get_stats64 = nsim_get_stats64, 31579579220SJakub Kicinski .ndo_set_vf_mac = nsim_set_vf_mac, 31679579220SJakub Kicinski .ndo_set_vf_vlan = nsim_set_vf_vlan, 31779579220SJakub Kicinski .ndo_set_vf_rate = nsim_set_vf_rate, 31879579220SJakub Kicinski .ndo_set_vf_spoofchk = nsim_set_vf_spoofchk, 31979579220SJakub Kicinski .ndo_set_vf_trust = nsim_set_vf_trust, 32079579220SJakub Kicinski .ndo_get_vf_config = nsim_get_vf_config, 32179579220SJakub Kicinski .ndo_set_vf_link_state = nsim_set_vf_link_state, 32279579220SJakub Kicinski .ndo_set_vf_rss_query_en = nsim_set_vf_rss_query_en, 32331d3ad83SJakub Kicinski .ndo_setup_tc = nsim_setup_tc, 32431d3ad83SJakub Kicinski .ndo_set_features = nsim_set_features, 32531d3ad83SJakub Kicinski .ndo_bpf = nsim_bpf, 326e58df56cSFlorian Fainelli .ndo_get_port_parent_id = nsim_get_port_parent_id, 32783c9e13aSJakub Kicinski }; 32883c9e13aSJakub Kicinski 32983c9e13aSJakub Kicinski static void nsim_setup(struct net_device *dev) 33083c9e13aSJakub Kicinski { 33183c9e13aSJakub Kicinski ether_setup(dev); 33283c9e13aSJakub Kicinski eth_hw_addr_random(dev); 33383c9e13aSJakub Kicinski 33483c9e13aSJakub Kicinski dev->netdev_ops = &nsim_netdev_ops; 335c3d9a435SJiri Pirko dev->needs_free_netdev = true; 33679579220SJakub Kicinski dev->priv_destructor = nsim_free; 33783c9e13aSJakub Kicinski 33883c9e13aSJakub Kicinski dev->tx_queue_len = 0; 33983c9e13aSJakub Kicinski dev->flags |= IFF_NOARP; 34083c9e13aSJakub Kicinski dev->flags &= ~IFF_MULTICAST; 34183c9e13aSJakub Kicinski dev->priv_flags |= IFF_LIVE_ADDR_CHANGE | 34283c9e13aSJakub Kicinski IFF_NO_QUEUE; 34383c9e13aSJakub Kicinski dev->features |= NETIF_F_HIGHDMA | 34483c9e13aSJakub Kicinski NETIF_F_SG | 34583c9e13aSJakub Kicinski NETIF_F_FRAGLIST | 34683c9e13aSJakub Kicinski NETIF_F_HW_CSUM | 34783c9e13aSJakub Kicinski NETIF_F_TSO; 34831d3ad83SJakub Kicinski dev->hw_features |= NETIF_F_HW_TC; 34983c9e13aSJakub Kicinski dev->max_mtu = ETH_MAX_MTU; 35083c9e13aSJakub Kicinski } 35183c9e13aSJakub Kicinski 35283c9e13aSJakub Kicinski static int nsim_validate(struct nlattr *tb[], struct nlattr *data[], 35383c9e13aSJakub Kicinski struct netlink_ext_ack *extack) 35483c9e13aSJakub Kicinski { 35583c9e13aSJakub Kicinski if (tb[IFLA_ADDRESS]) { 35683c9e13aSJakub Kicinski if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN) 35783c9e13aSJakub Kicinski return -EINVAL; 35883c9e13aSJakub Kicinski if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS]))) 35983c9e13aSJakub Kicinski return -EADDRNOTAVAIL; 36083c9e13aSJakub Kicinski } 36183c9e13aSJakub Kicinski return 0; 36283c9e13aSJakub Kicinski } 36383c9e13aSJakub Kicinski 364eeeaaf18SJakub Kicinski static int nsim_newlink(struct net *src_net, struct net_device *dev, 365eeeaaf18SJakub Kicinski struct nlattr *tb[], struct nlattr *data[], 366eeeaaf18SJakub Kicinski struct netlink_ext_ack *extack) 367eeeaaf18SJakub Kicinski { 368eeeaaf18SJakub Kicinski struct netdevsim *ns = netdev_priv(dev); 369af9095f0SJiri Pirko struct netdevsim *joinns = NULL; 370af9095f0SJiri Pirko int err; 371eeeaaf18SJakub Kicinski 372eeeaaf18SJakub Kicinski if (tb[IFLA_LINK]) { 373eeeaaf18SJakub Kicinski struct net_device *joindev; 374eeeaaf18SJakub Kicinski 375eeeaaf18SJakub Kicinski joindev = __dev_get_by_index(src_net, 376eeeaaf18SJakub Kicinski nla_get_u32(tb[IFLA_LINK])); 377eeeaaf18SJakub Kicinski if (!joindev) 378eeeaaf18SJakub Kicinski return -ENODEV; 379eeeaaf18SJakub Kicinski if (joindev->netdev_ops != &nsim_netdev_ops) 380eeeaaf18SJakub Kicinski return -EINVAL; 381eeeaaf18SJakub Kicinski 382eeeaaf18SJakub Kicinski joinns = netdev_priv(joindev); 383eeeaaf18SJakub Kicinski } 384eeeaaf18SJakub Kicinski 385af9095f0SJiri Pirko ns->sdev = nsim_sdev_get(joinns); 386af9095f0SJiri Pirko if (IS_ERR(ns->sdev)) 387af9095f0SJiri Pirko return PTR_ERR(ns->sdev); 388af9095f0SJiri Pirko 389*40e4fe4cSJiri Pirko ns->nsim_bus_dev = nsim_bus_dev_new(); 390*40e4fe4cSJiri Pirko if (IS_ERR(ns->nsim_bus_dev)) { 391*40e4fe4cSJiri Pirko err = PTR_ERR(ns->nsim_bus_dev); 392af9095f0SJiri Pirko goto err_sdev_put; 393*40e4fe4cSJiri Pirko } 3941daf36c0SJiri Pirko 395*40e4fe4cSJiri Pirko SET_NETDEV_DEV(dev, &ns->nsim_bus_dev->dev); 3965fc49422SJiri Pirko ns->netdev = dev; 3975fc49422SJiri Pirko 3988fb4bc6fSJiri Pirko err = nsim_dev_init(ns); 3995fc49422SJiri Pirko if (err) 400*40e4fe4cSJiri Pirko goto err_dev_del; 4011daf36c0SJiri Pirko 4021daf36c0SJiri Pirko err = register_netdevice(dev); 4031daf36c0SJiri Pirko if (err) 4048fb4bc6fSJiri Pirko goto err_dev_exit; 405af9095f0SJiri Pirko return 0; 406af9095f0SJiri Pirko 4078fb4bc6fSJiri Pirko err_dev_exit: 4088fb4bc6fSJiri Pirko nsim_dev_exit(ns); 409*40e4fe4cSJiri Pirko err_dev_del: 410*40e4fe4cSJiri Pirko nsim_bus_dev_del(ns->nsim_bus_dev); 411af9095f0SJiri Pirko err_sdev_put: 412af9095f0SJiri Pirko nsim_sdev_put(ns->sdev); 413af9095f0SJiri Pirko return err; 414eeeaaf18SJakub Kicinski } 415eeeaaf18SJakub Kicinski 41683c9e13aSJakub Kicinski static struct rtnl_link_ops nsim_link_ops __read_mostly = { 41783c9e13aSJakub Kicinski .kind = DRV_NAME, 41883c9e13aSJakub Kicinski .priv_size = sizeof(struct netdevsim), 41983c9e13aSJakub Kicinski .setup = nsim_setup, 42083c9e13aSJakub Kicinski .validate = nsim_validate, 421eeeaaf18SJakub Kicinski .newlink = nsim_newlink, 42283c9e13aSJakub Kicinski }; 42383c9e13aSJakub Kicinski 42483c9e13aSJakub Kicinski static int __init nsim_module_init(void) 42583c9e13aSJakub Kicinski { 42631d3ad83SJakub Kicinski int err; 42731d3ad83SJakub Kicinski 42831d3ad83SJakub Kicinski nsim_ddir = debugfs_create_dir(DRV_NAME, NULL); 4299ee1942cSPrashant Bhole if (IS_ERR_OR_NULL(nsim_ddir)) 4309ee1942cSPrashant Bhole return -ENOMEM; 43131d3ad83SJakub Kicinski 432af9095f0SJiri Pirko err = nsim_sdev_init(); 433af9095f0SJiri Pirko if (err) 434eeeaaf18SJakub Kicinski goto err_debugfs_destroy; 435eeeaaf18SJakub Kicinski 436925f5afeSJiri Pirko err = nsim_bus_init(); 43731d3ad83SJakub Kicinski if (err) 438af9095f0SJiri Pirko goto err_sdev_exit; 43931d3ad83SJakub Kicinski 4405fc49422SJiri Pirko err = rtnl_link_register(&nsim_link_ops); 44179579220SJakub Kicinski if (err) 442925f5afeSJiri Pirko goto err_bus_exit; 44379579220SJakub Kicinski 44431d3ad83SJakub Kicinski return 0; 44531d3ad83SJakub Kicinski 446925f5afeSJiri Pirko err_bus_exit: 447925f5afeSJiri Pirko nsim_bus_exit(); 448af9095f0SJiri Pirko err_sdev_exit: 449af9095f0SJiri Pirko nsim_sdev_exit(); 45031d3ad83SJakub Kicinski err_debugfs_destroy: 45131d3ad83SJakub Kicinski debugfs_remove_recursive(nsim_ddir); 45231d3ad83SJakub Kicinski return err; 45383c9e13aSJakub Kicinski } 45483c9e13aSJakub Kicinski 45583c9e13aSJakub Kicinski static void __exit nsim_module_exit(void) 45683c9e13aSJakub Kicinski { 45783c9e13aSJakub Kicinski rtnl_link_unregister(&nsim_link_ops); 458925f5afeSJiri Pirko nsim_bus_exit(); 459af9095f0SJiri Pirko nsim_sdev_exit(); 46031d3ad83SJakub Kicinski debugfs_remove_recursive(nsim_ddir); 46183c9e13aSJakub Kicinski } 46283c9e13aSJakub Kicinski 46383c9e13aSJakub Kicinski module_init(nsim_module_init); 46483c9e13aSJakub Kicinski module_exit(nsim_module_exit); 46583c9e13aSJakub Kicinski MODULE_LICENSE("GPL"); 46683c9e13aSJakub Kicinski MODULE_ALIAS_RTNL_LINK(DRV_NAME); 467