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 35*d514f41eSJiri Pirko ppid->id_len = sizeof(ns->nsim_dev->nsim_bus_dev->dev.id); 36*d514f41eSJiri Pirko memcpy(&ppid->id, &ns->nsim_dev->nsim_bus_dev->dev.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); 43*d514f41eSJiri Pirko char dev_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 50*d514f41eSJiri Pirko sprintf(dev_link_name, "../../" DRV_NAME "_dev/%u", 51*d514f41eSJiri Pirko ns->nsim_dev->nsim_bus_dev->dev.id); 52*d514f41eSJiri Pirko debugfs_create_symlink("dev", ns->ddir, dev_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 80a60f9e48SJiri Pirko nsim_dev_destroy(ns->nsim_dev); 8140e4fe4cSJiri Pirko nsim_bus_dev_del(ns->nsim_bus_dev); 8279579220SJakub Kicinski /* netdev and vf state will be freed out of device_release() */ 8379579220SJakub Kicinski } 8479579220SJakub Kicinski 8583c9e13aSJakub Kicinski static netdev_tx_t nsim_start_xmit(struct sk_buff *skb, struct net_device *dev) 8683c9e13aSJakub Kicinski { 8783c9e13aSJakub Kicinski struct netdevsim *ns = netdev_priv(dev); 8883c9e13aSJakub Kicinski 897699353dSShannon Nelson if (!nsim_ipsec_tx(ns, skb)) 907699353dSShannon Nelson goto out; 917699353dSShannon Nelson 9283c9e13aSJakub Kicinski u64_stats_update_begin(&ns->syncp); 9383c9e13aSJakub Kicinski ns->tx_packets++; 9483c9e13aSJakub Kicinski ns->tx_bytes += skb->len; 9583c9e13aSJakub Kicinski u64_stats_update_end(&ns->syncp); 9683c9e13aSJakub Kicinski 977699353dSShannon Nelson out: 9883c9e13aSJakub Kicinski dev_kfree_skb(skb); 9983c9e13aSJakub Kicinski 10083c9e13aSJakub Kicinski return NETDEV_TX_OK; 10183c9e13aSJakub Kicinski } 10283c9e13aSJakub Kicinski 10383c9e13aSJakub Kicinski static void nsim_set_rx_mode(struct net_device *dev) 10483c9e13aSJakub Kicinski { 10583c9e13aSJakub Kicinski } 10683c9e13aSJakub Kicinski 10731d3ad83SJakub Kicinski static int nsim_change_mtu(struct net_device *dev, int new_mtu) 10831d3ad83SJakub Kicinski { 10931d3ad83SJakub Kicinski struct netdevsim *ns = netdev_priv(dev); 11031d3ad83SJakub Kicinski 111799e173dSJakub Kicinski if (ns->xdp.prog && new_mtu > NSIM_XDP_MAX_MTU) 11231d3ad83SJakub Kicinski return -EBUSY; 11331d3ad83SJakub Kicinski 11431d3ad83SJakub Kicinski dev->mtu = new_mtu; 11531d3ad83SJakub Kicinski 11631d3ad83SJakub Kicinski return 0; 11731d3ad83SJakub Kicinski } 11831d3ad83SJakub Kicinski 11983c9e13aSJakub Kicinski static void 12083c9e13aSJakub Kicinski nsim_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) 12183c9e13aSJakub Kicinski { 12283c9e13aSJakub Kicinski struct netdevsim *ns = netdev_priv(dev); 12383c9e13aSJakub Kicinski unsigned int start; 12483c9e13aSJakub Kicinski 12583c9e13aSJakub Kicinski do { 12683c9e13aSJakub Kicinski start = u64_stats_fetch_begin(&ns->syncp); 12783c9e13aSJakub Kicinski stats->tx_bytes = ns->tx_bytes; 12883c9e13aSJakub Kicinski stats->tx_packets = ns->tx_packets; 12983c9e13aSJakub Kicinski } while (u64_stats_fetch_retry(&ns->syncp, start)); 13083c9e13aSJakub Kicinski } 13183c9e13aSJakub Kicinski 13231d3ad83SJakub Kicinski static int 13331d3ad83SJakub Kicinski nsim_setup_tc_block_cb(enum tc_setup_type type, void *type_data, void *cb_priv) 13431d3ad83SJakub Kicinski { 13531d3ad83SJakub Kicinski return nsim_bpf_setup_tc_block_cb(type, type_data, cb_priv); 13631d3ad83SJakub Kicinski } 13731d3ad83SJakub Kicinski 13831d3ad83SJakub Kicinski static int 13931d3ad83SJakub Kicinski nsim_setup_tc_block(struct net_device *dev, struct tc_block_offload *f) 14031d3ad83SJakub Kicinski { 14131d3ad83SJakub Kicinski struct netdevsim *ns = netdev_priv(dev); 14231d3ad83SJakub Kicinski 14331d3ad83SJakub Kicinski if (f->binder_type != TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS) 14431d3ad83SJakub Kicinski return -EOPNOTSUPP; 14531d3ad83SJakub Kicinski 14631d3ad83SJakub Kicinski switch (f->command) { 14731d3ad83SJakub Kicinski case TC_BLOCK_BIND: 14831d3ad83SJakub Kicinski return tcf_block_cb_register(f->block, nsim_setup_tc_block_cb, 14960513bd8SJohn Hurley ns, ns, f->extack); 15031d3ad83SJakub Kicinski case TC_BLOCK_UNBIND: 15131d3ad83SJakub Kicinski tcf_block_cb_unregister(f->block, nsim_setup_tc_block_cb, ns); 15231d3ad83SJakub Kicinski return 0; 15331d3ad83SJakub Kicinski default: 15431d3ad83SJakub Kicinski return -EOPNOTSUPP; 15531d3ad83SJakub Kicinski } 15631d3ad83SJakub Kicinski } 15731d3ad83SJakub Kicinski 15879579220SJakub Kicinski static int nsim_set_vf_mac(struct net_device *dev, int vf, u8 *mac) 15979579220SJakub Kicinski { 16079579220SJakub Kicinski struct netdevsim *ns = netdev_priv(dev); 16140e4fe4cSJiri Pirko struct nsim_bus_dev *nsim_bus_dev = ns->nsim_bus_dev; 16279579220SJakub Kicinski 16379579220SJakub Kicinski /* Only refuse multicast addresses, zero address can mean unset/any. */ 16440e4fe4cSJiri Pirko if (vf >= nsim_bus_dev->num_vfs || is_multicast_ether_addr(mac)) 16579579220SJakub Kicinski return -EINVAL; 16640e4fe4cSJiri Pirko memcpy(nsim_bus_dev->vfconfigs[vf].vf_mac, mac, ETH_ALEN); 16779579220SJakub Kicinski 16879579220SJakub Kicinski return 0; 16979579220SJakub Kicinski } 17079579220SJakub Kicinski 17179579220SJakub Kicinski static int nsim_set_vf_vlan(struct net_device *dev, int vf, 17279579220SJakub Kicinski u16 vlan, u8 qos, __be16 vlan_proto) 17379579220SJakub Kicinski { 17479579220SJakub Kicinski struct netdevsim *ns = netdev_priv(dev); 17540e4fe4cSJiri Pirko struct nsim_bus_dev *nsim_bus_dev = ns->nsim_bus_dev; 17679579220SJakub Kicinski 17740e4fe4cSJiri Pirko if (vf >= nsim_bus_dev->num_vfs || vlan > 4095 || qos > 7) 17879579220SJakub Kicinski return -EINVAL; 17979579220SJakub Kicinski 18040e4fe4cSJiri Pirko nsim_bus_dev->vfconfigs[vf].vlan = vlan; 18140e4fe4cSJiri Pirko nsim_bus_dev->vfconfigs[vf].qos = qos; 18240e4fe4cSJiri Pirko nsim_bus_dev->vfconfigs[vf].vlan_proto = vlan_proto; 18379579220SJakub Kicinski 18479579220SJakub Kicinski return 0; 18579579220SJakub Kicinski } 18679579220SJakub Kicinski 18779579220SJakub Kicinski static int nsim_set_vf_rate(struct net_device *dev, int vf, int min, int max) 18879579220SJakub Kicinski { 18979579220SJakub Kicinski struct netdevsim *ns = netdev_priv(dev); 19040e4fe4cSJiri Pirko struct nsim_bus_dev *nsim_bus_dev = ns->nsim_bus_dev; 19179579220SJakub Kicinski 19240e4fe4cSJiri Pirko if (vf >= nsim_bus_dev->num_vfs) 19379579220SJakub Kicinski return -EINVAL; 19479579220SJakub Kicinski 19540e4fe4cSJiri Pirko nsim_bus_dev->vfconfigs[vf].min_tx_rate = min; 19640e4fe4cSJiri Pirko nsim_bus_dev->vfconfigs[vf].max_tx_rate = max; 19779579220SJakub Kicinski 19879579220SJakub Kicinski return 0; 19979579220SJakub Kicinski } 20079579220SJakub Kicinski 20179579220SJakub Kicinski static int nsim_set_vf_spoofchk(struct net_device *dev, int vf, bool val) 20279579220SJakub Kicinski { 20379579220SJakub Kicinski struct netdevsim *ns = netdev_priv(dev); 20440e4fe4cSJiri Pirko struct nsim_bus_dev *nsim_bus_dev = ns->nsim_bus_dev; 20579579220SJakub Kicinski 20640e4fe4cSJiri Pirko if (vf >= nsim_bus_dev->num_vfs) 20779579220SJakub Kicinski return -EINVAL; 20840e4fe4cSJiri Pirko nsim_bus_dev->vfconfigs[vf].spoofchk_enabled = val; 20979579220SJakub Kicinski 21079579220SJakub Kicinski return 0; 21179579220SJakub Kicinski } 21279579220SJakub Kicinski 21379579220SJakub Kicinski static int nsim_set_vf_rss_query_en(struct net_device *dev, int vf, bool val) 21479579220SJakub Kicinski { 21579579220SJakub Kicinski struct netdevsim *ns = netdev_priv(dev); 21640e4fe4cSJiri Pirko struct nsim_bus_dev *nsim_bus_dev = ns->nsim_bus_dev; 21779579220SJakub Kicinski 21840e4fe4cSJiri Pirko if (vf >= nsim_bus_dev->num_vfs) 21979579220SJakub Kicinski return -EINVAL; 22040e4fe4cSJiri Pirko nsim_bus_dev->vfconfigs[vf].rss_query_enabled = val; 22179579220SJakub Kicinski 22279579220SJakub Kicinski return 0; 22379579220SJakub Kicinski } 22479579220SJakub Kicinski 22579579220SJakub Kicinski static int nsim_set_vf_trust(struct net_device *dev, int vf, bool val) 22679579220SJakub Kicinski { 22779579220SJakub Kicinski struct netdevsim *ns = netdev_priv(dev); 22840e4fe4cSJiri Pirko struct nsim_bus_dev *nsim_bus_dev = ns->nsim_bus_dev; 22979579220SJakub Kicinski 23040e4fe4cSJiri Pirko if (vf >= nsim_bus_dev->num_vfs) 23179579220SJakub Kicinski return -EINVAL; 23240e4fe4cSJiri Pirko nsim_bus_dev->vfconfigs[vf].trusted = val; 23379579220SJakub Kicinski 23479579220SJakub Kicinski return 0; 23579579220SJakub Kicinski } 23679579220SJakub Kicinski 23779579220SJakub Kicinski static int 23879579220SJakub Kicinski nsim_get_vf_config(struct net_device *dev, int vf, struct ifla_vf_info *ivi) 23979579220SJakub Kicinski { 24079579220SJakub Kicinski struct netdevsim *ns = netdev_priv(dev); 24140e4fe4cSJiri Pirko struct nsim_bus_dev *nsim_bus_dev = ns->nsim_bus_dev; 24279579220SJakub Kicinski 24340e4fe4cSJiri Pirko if (vf >= nsim_bus_dev->num_vfs) 24479579220SJakub Kicinski return -EINVAL; 24579579220SJakub Kicinski 24679579220SJakub Kicinski ivi->vf = vf; 24740e4fe4cSJiri Pirko ivi->linkstate = nsim_bus_dev->vfconfigs[vf].link_state; 24840e4fe4cSJiri Pirko ivi->min_tx_rate = nsim_bus_dev->vfconfigs[vf].min_tx_rate; 24940e4fe4cSJiri Pirko ivi->max_tx_rate = nsim_bus_dev->vfconfigs[vf].max_tx_rate; 25040e4fe4cSJiri Pirko ivi->vlan = nsim_bus_dev->vfconfigs[vf].vlan; 25140e4fe4cSJiri Pirko ivi->vlan_proto = nsim_bus_dev->vfconfigs[vf].vlan_proto; 25240e4fe4cSJiri Pirko ivi->qos = nsim_bus_dev->vfconfigs[vf].qos; 25340e4fe4cSJiri Pirko memcpy(&ivi->mac, nsim_bus_dev->vfconfigs[vf].vf_mac, ETH_ALEN); 25440e4fe4cSJiri Pirko ivi->spoofchk = nsim_bus_dev->vfconfigs[vf].spoofchk_enabled; 25540e4fe4cSJiri Pirko ivi->trusted = nsim_bus_dev->vfconfigs[vf].trusted; 25640e4fe4cSJiri Pirko ivi->rss_query_en = nsim_bus_dev->vfconfigs[vf].rss_query_enabled; 25779579220SJakub Kicinski 25879579220SJakub Kicinski return 0; 25979579220SJakub Kicinski } 26079579220SJakub Kicinski 26179579220SJakub Kicinski static int nsim_set_vf_link_state(struct net_device *dev, int vf, int state) 26279579220SJakub Kicinski { 26379579220SJakub Kicinski struct netdevsim *ns = netdev_priv(dev); 26440e4fe4cSJiri Pirko struct nsim_bus_dev *nsim_bus_dev = ns->nsim_bus_dev; 26579579220SJakub Kicinski 26640e4fe4cSJiri Pirko if (vf >= nsim_bus_dev->num_vfs) 26779579220SJakub Kicinski return -EINVAL; 26879579220SJakub Kicinski 26979579220SJakub Kicinski switch (state) { 27079579220SJakub Kicinski case IFLA_VF_LINK_STATE_AUTO: 27179579220SJakub Kicinski case IFLA_VF_LINK_STATE_ENABLE: 27279579220SJakub Kicinski case IFLA_VF_LINK_STATE_DISABLE: 27379579220SJakub Kicinski break; 27479579220SJakub Kicinski default: 27579579220SJakub Kicinski return -EINVAL; 27679579220SJakub Kicinski } 27779579220SJakub Kicinski 27840e4fe4cSJiri Pirko nsim_bus_dev->vfconfigs[vf].link_state = state; 27979579220SJakub Kicinski 28079579220SJakub Kicinski return 0; 28179579220SJakub Kicinski } 28279579220SJakub Kicinski 28331d3ad83SJakub Kicinski static int 28431d3ad83SJakub Kicinski nsim_setup_tc(struct net_device *dev, enum tc_setup_type type, void *type_data) 28531d3ad83SJakub Kicinski { 28631d3ad83SJakub Kicinski switch (type) { 28731d3ad83SJakub Kicinski case TC_SETUP_BLOCK: 28831d3ad83SJakub Kicinski return nsim_setup_tc_block(dev, type_data); 28931d3ad83SJakub Kicinski default: 29031d3ad83SJakub Kicinski return -EOPNOTSUPP; 29131d3ad83SJakub Kicinski } 29231d3ad83SJakub Kicinski } 29331d3ad83SJakub Kicinski 29431d3ad83SJakub Kicinski static int 29531d3ad83SJakub Kicinski nsim_set_features(struct net_device *dev, netdev_features_t features) 29631d3ad83SJakub Kicinski { 29731d3ad83SJakub Kicinski struct netdevsim *ns = netdev_priv(dev); 29831d3ad83SJakub Kicinski 29931d3ad83SJakub Kicinski if ((dev->features & NETIF_F_HW_TC) > (features & NETIF_F_HW_TC)) 30031d3ad83SJakub Kicinski return nsim_bpf_disable_tc(ns); 30131d3ad83SJakub Kicinski 30231d3ad83SJakub Kicinski return 0; 30331d3ad83SJakub Kicinski } 30431d3ad83SJakub Kicinski 30583c9e13aSJakub Kicinski static const struct net_device_ops nsim_netdev_ops = { 30631d3ad83SJakub Kicinski .ndo_init = nsim_init, 30731d3ad83SJakub Kicinski .ndo_uninit = nsim_uninit, 30883c9e13aSJakub Kicinski .ndo_start_xmit = nsim_start_xmit, 30983c9e13aSJakub Kicinski .ndo_set_rx_mode = nsim_set_rx_mode, 31083c9e13aSJakub Kicinski .ndo_set_mac_address = eth_mac_addr, 31183c9e13aSJakub Kicinski .ndo_validate_addr = eth_validate_addr, 31231d3ad83SJakub Kicinski .ndo_change_mtu = nsim_change_mtu, 31383c9e13aSJakub Kicinski .ndo_get_stats64 = nsim_get_stats64, 31479579220SJakub Kicinski .ndo_set_vf_mac = nsim_set_vf_mac, 31579579220SJakub Kicinski .ndo_set_vf_vlan = nsim_set_vf_vlan, 31679579220SJakub Kicinski .ndo_set_vf_rate = nsim_set_vf_rate, 31779579220SJakub Kicinski .ndo_set_vf_spoofchk = nsim_set_vf_spoofchk, 31879579220SJakub Kicinski .ndo_set_vf_trust = nsim_set_vf_trust, 31979579220SJakub Kicinski .ndo_get_vf_config = nsim_get_vf_config, 32079579220SJakub Kicinski .ndo_set_vf_link_state = nsim_set_vf_link_state, 32179579220SJakub Kicinski .ndo_set_vf_rss_query_en = nsim_set_vf_rss_query_en, 32231d3ad83SJakub Kicinski .ndo_setup_tc = nsim_setup_tc, 32331d3ad83SJakub Kicinski .ndo_set_features = nsim_set_features, 32431d3ad83SJakub Kicinski .ndo_bpf = nsim_bpf, 325e58df56cSFlorian Fainelli .ndo_get_port_parent_id = nsim_get_port_parent_id, 32683c9e13aSJakub Kicinski }; 32783c9e13aSJakub Kicinski 32883c9e13aSJakub Kicinski static void nsim_setup(struct net_device *dev) 32983c9e13aSJakub Kicinski { 33083c9e13aSJakub Kicinski ether_setup(dev); 33183c9e13aSJakub Kicinski eth_hw_addr_random(dev); 33283c9e13aSJakub Kicinski 33383c9e13aSJakub Kicinski dev->netdev_ops = &nsim_netdev_ops; 334c3d9a435SJiri Pirko dev->needs_free_netdev = true; 33579579220SJakub Kicinski dev->priv_destructor = nsim_free; 33683c9e13aSJakub Kicinski 33783c9e13aSJakub Kicinski dev->tx_queue_len = 0; 33883c9e13aSJakub Kicinski dev->flags |= IFF_NOARP; 33983c9e13aSJakub Kicinski dev->flags &= ~IFF_MULTICAST; 34083c9e13aSJakub Kicinski dev->priv_flags |= IFF_LIVE_ADDR_CHANGE | 34183c9e13aSJakub Kicinski IFF_NO_QUEUE; 34283c9e13aSJakub Kicinski dev->features |= NETIF_F_HIGHDMA | 34383c9e13aSJakub Kicinski NETIF_F_SG | 34483c9e13aSJakub Kicinski NETIF_F_FRAGLIST | 34583c9e13aSJakub Kicinski NETIF_F_HW_CSUM | 34683c9e13aSJakub Kicinski NETIF_F_TSO; 34731d3ad83SJakub Kicinski dev->hw_features |= NETIF_F_HW_TC; 34883c9e13aSJakub Kicinski dev->max_mtu = ETH_MAX_MTU; 34983c9e13aSJakub Kicinski } 35083c9e13aSJakub Kicinski 35183c9e13aSJakub Kicinski static int nsim_validate(struct nlattr *tb[], struct nlattr *data[], 35283c9e13aSJakub Kicinski struct netlink_ext_ack *extack) 35383c9e13aSJakub Kicinski { 35483c9e13aSJakub Kicinski if (tb[IFLA_ADDRESS]) { 35583c9e13aSJakub Kicinski if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN) 35683c9e13aSJakub Kicinski return -EINVAL; 35783c9e13aSJakub Kicinski if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS]))) 35883c9e13aSJakub Kicinski return -EADDRNOTAVAIL; 35983c9e13aSJakub Kicinski } 36083c9e13aSJakub Kicinski return 0; 36183c9e13aSJakub Kicinski } 36283c9e13aSJakub Kicinski 363eeeaaf18SJakub Kicinski static int nsim_newlink(struct net *src_net, struct net_device *dev, 364eeeaaf18SJakub Kicinski struct nlattr *tb[], struct nlattr *data[], 365eeeaaf18SJakub Kicinski struct netlink_ext_ack *extack) 366eeeaaf18SJakub Kicinski { 367eeeaaf18SJakub Kicinski struct netdevsim *ns = netdev_priv(dev); 368af9095f0SJiri Pirko int err; 369eeeaaf18SJakub Kicinski 370f9d9db47SJiri Pirko ns->nsim_bus_dev = nsim_bus_dev_new(~0, 0); 371*d514f41eSJiri Pirko if (IS_ERR(ns->nsim_bus_dev)) 372*d514f41eSJiri Pirko return PTR_ERR(ns->nsim_bus_dev); 3731daf36c0SJiri Pirko 37440e4fe4cSJiri Pirko SET_NETDEV_DEV(dev, &ns->nsim_bus_dev->dev); 3755fc49422SJiri Pirko ns->netdev = dev; 3765fc49422SJiri Pirko 377a60f9e48SJiri Pirko ns->nsim_dev = nsim_dev_create_with_ns(ns->nsim_bus_dev, ns); 378a60f9e48SJiri Pirko if (IS_ERR(ns->nsim_dev)) { 379a60f9e48SJiri Pirko err = PTR_ERR(ns->nsim_dev); 38040e4fe4cSJiri Pirko goto err_dev_del; 381a60f9e48SJiri Pirko } 3821daf36c0SJiri Pirko 3831daf36c0SJiri Pirko err = register_netdevice(dev); 3841daf36c0SJiri Pirko if (err) 385a60f9e48SJiri Pirko goto err_dev_destroy; 386af9095f0SJiri Pirko return 0; 387af9095f0SJiri Pirko 388a60f9e48SJiri Pirko err_dev_destroy: 389a60f9e48SJiri Pirko nsim_dev_destroy(ns->nsim_dev); 39040e4fe4cSJiri Pirko err_dev_del: 39140e4fe4cSJiri Pirko nsim_bus_dev_del(ns->nsim_bus_dev); 392af9095f0SJiri Pirko return err; 393eeeaaf18SJakub Kicinski } 394eeeaaf18SJakub Kicinski 39583c9e13aSJakub Kicinski static struct rtnl_link_ops nsim_link_ops __read_mostly = { 39683c9e13aSJakub Kicinski .kind = DRV_NAME, 39783c9e13aSJakub Kicinski .priv_size = sizeof(struct netdevsim), 39883c9e13aSJakub Kicinski .setup = nsim_setup, 39983c9e13aSJakub Kicinski .validate = nsim_validate, 400eeeaaf18SJakub Kicinski .newlink = nsim_newlink, 40183c9e13aSJakub Kicinski }; 40283c9e13aSJakub Kicinski 40383c9e13aSJakub Kicinski static int __init nsim_module_init(void) 40483c9e13aSJakub Kicinski { 40531d3ad83SJakub Kicinski int err; 40631d3ad83SJakub Kicinski 40731d3ad83SJakub Kicinski nsim_ddir = debugfs_create_dir(DRV_NAME, NULL); 4089ee1942cSPrashant Bhole if (IS_ERR_OR_NULL(nsim_ddir)) 4099ee1942cSPrashant Bhole return -ENOMEM; 41031d3ad83SJakub Kicinski 411*d514f41eSJiri Pirko err = nsim_dev_init(); 412af9095f0SJiri Pirko if (err) 413eeeaaf18SJakub Kicinski goto err_debugfs_destroy; 414eeeaaf18SJakub Kicinski 415925f5afeSJiri Pirko err = nsim_bus_init(); 41631d3ad83SJakub Kicinski if (err) 417*d514f41eSJiri Pirko goto err_dev_exit; 41831d3ad83SJakub Kicinski 4195fc49422SJiri Pirko err = rtnl_link_register(&nsim_link_ops); 42079579220SJakub Kicinski if (err) 421925f5afeSJiri Pirko goto err_bus_exit; 42279579220SJakub Kicinski 42331d3ad83SJakub Kicinski return 0; 42431d3ad83SJakub Kicinski 425925f5afeSJiri Pirko err_bus_exit: 426925f5afeSJiri Pirko nsim_bus_exit(); 427*d514f41eSJiri Pirko err_dev_exit: 428*d514f41eSJiri Pirko nsim_dev_exit(); 42931d3ad83SJakub Kicinski err_debugfs_destroy: 43031d3ad83SJakub Kicinski debugfs_remove_recursive(nsim_ddir); 43131d3ad83SJakub Kicinski return err; 43283c9e13aSJakub Kicinski } 43383c9e13aSJakub Kicinski 43483c9e13aSJakub Kicinski static void __exit nsim_module_exit(void) 43583c9e13aSJakub Kicinski { 43683c9e13aSJakub Kicinski rtnl_link_unregister(&nsim_link_ops); 437925f5afeSJiri Pirko nsim_bus_exit(); 438*d514f41eSJiri Pirko nsim_dev_exit(); 43931d3ad83SJakub Kicinski debugfs_remove_recursive(nsim_ddir); 44083c9e13aSJakub Kicinski } 44183c9e13aSJakub Kicinski 44283c9e13aSJakub Kicinski module_init(nsim_module_init); 44383c9e13aSJakub Kicinski module_exit(nsim_module_exit); 44483c9e13aSJakub Kicinski MODULE_LICENSE("GPL"); 44583c9e13aSJakub Kicinski MODULE_ALIAS_RTNL_LINK(DRV_NAME); 446