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 28e58df56cSFlorian Fainelli static int nsim_get_port_parent_id(struct net_device *dev, 29e58df56cSFlorian Fainelli struct netdev_phys_item_id *ppid) 305f07655bSJakub Kicinski { 315f07655bSJakub Kicinski struct netdevsim *ns = netdev_priv(dev); 325f07655bSJakub Kicinski 33514cf64cSJiri Pirko memcpy(ppid, &ns->nsim_dev->switch_id, sizeof(*ppid)); 345f07655bSJakub Kicinski return 0; 355f07655bSJakub Kicinski } 365f07655bSJakub Kicinski 3731d3ad83SJakub Kicinski static int nsim_init(struct net_device *dev) 3831d3ad83SJakub Kicinski { 3931d3ad83SJakub Kicinski struct netdevsim *ns = netdev_priv(dev); 40d514f41eSJiri Pirko char dev_link_name[32]; 4131d3ad83SJakub Kicinski int err; 4231d3ad83SJakub Kicinski 43*ab1d0cc0SJiri Pirko ns->ddir = debugfs_create_dir("0", ns->nsim_dev->ports_ddir); 449ee1942cSPrashant Bhole if (IS_ERR_OR_NULL(ns->ddir)) 459ee1942cSPrashant Bhole return -ENOMEM; 4631d3ad83SJakub Kicinski 47*ab1d0cc0SJiri Pirko sprintf(dev_link_name, "../../../" DRV_NAME "%u", 48d514f41eSJiri Pirko ns->nsim_dev->nsim_bus_dev->dev.id); 49d514f41eSJiri Pirko debugfs_create_symlink("dev", ns->ddir, dev_link_name); 50eeeaaf18SJakub Kicinski 5131d3ad83SJakub Kicinski err = nsim_bpf_init(ns); 5231d3ad83SJakub Kicinski if (err) 53af9095f0SJiri Pirko goto err_debugfs_destroy; 5431d3ad83SJakub Kicinski 557699353dSShannon Nelson nsim_ipsec_init(ns); 567699353dSShannon Nelson 5731d3ad83SJakub Kicinski return 0; 5831d3ad83SJakub Kicinski 5931d3ad83SJakub Kicinski err_debugfs_destroy: 6031d3ad83SJakub Kicinski debugfs_remove_recursive(ns->ddir); 6131d3ad83SJakub Kicinski return err; 6231d3ad83SJakub Kicinski } 6331d3ad83SJakub Kicinski 6431d3ad83SJakub Kicinski static void nsim_uninit(struct net_device *dev) 6531d3ad83SJakub Kicinski { 6631d3ad83SJakub Kicinski struct netdevsim *ns = netdev_priv(dev); 6731d3ad83SJakub Kicinski 687699353dSShannon Nelson nsim_ipsec_teardown(ns); 6931d3ad83SJakub Kicinski debugfs_remove_recursive(ns->ddir); 7031d3ad83SJakub Kicinski nsim_bpf_uninit(ns); 7131d3ad83SJakub Kicinski } 7231d3ad83SJakub Kicinski 7379579220SJakub Kicinski static void nsim_free(struct net_device *dev) 7479579220SJakub Kicinski { 7579579220SJakub Kicinski struct netdevsim *ns = netdev_priv(dev); 7679579220SJakub Kicinski 77a60f9e48SJiri Pirko nsim_dev_destroy(ns->nsim_dev); 7840e4fe4cSJiri Pirko nsim_bus_dev_del(ns->nsim_bus_dev); 7979579220SJakub Kicinski /* netdev and vf state will be freed out of device_release() */ 8079579220SJakub Kicinski } 8179579220SJakub Kicinski 8283c9e13aSJakub Kicinski static netdev_tx_t nsim_start_xmit(struct sk_buff *skb, struct net_device *dev) 8383c9e13aSJakub Kicinski { 8483c9e13aSJakub Kicinski struct netdevsim *ns = netdev_priv(dev); 8583c9e13aSJakub Kicinski 867699353dSShannon Nelson if (!nsim_ipsec_tx(ns, skb)) 877699353dSShannon Nelson goto out; 887699353dSShannon Nelson 8983c9e13aSJakub Kicinski u64_stats_update_begin(&ns->syncp); 9083c9e13aSJakub Kicinski ns->tx_packets++; 9183c9e13aSJakub Kicinski ns->tx_bytes += skb->len; 9283c9e13aSJakub Kicinski u64_stats_update_end(&ns->syncp); 9383c9e13aSJakub Kicinski 947699353dSShannon Nelson out: 9583c9e13aSJakub Kicinski dev_kfree_skb(skb); 9683c9e13aSJakub Kicinski 9783c9e13aSJakub Kicinski return NETDEV_TX_OK; 9883c9e13aSJakub Kicinski } 9983c9e13aSJakub Kicinski 10083c9e13aSJakub Kicinski static void nsim_set_rx_mode(struct net_device *dev) 10183c9e13aSJakub Kicinski { 10283c9e13aSJakub Kicinski } 10383c9e13aSJakub Kicinski 10431d3ad83SJakub Kicinski static int nsim_change_mtu(struct net_device *dev, int new_mtu) 10531d3ad83SJakub Kicinski { 10631d3ad83SJakub Kicinski struct netdevsim *ns = netdev_priv(dev); 10731d3ad83SJakub Kicinski 108799e173dSJakub Kicinski if (ns->xdp.prog && new_mtu > NSIM_XDP_MAX_MTU) 10931d3ad83SJakub Kicinski return -EBUSY; 11031d3ad83SJakub Kicinski 11131d3ad83SJakub Kicinski dev->mtu = new_mtu; 11231d3ad83SJakub Kicinski 11331d3ad83SJakub Kicinski return 0; 11431d3ad83SJakub Kicinski } 11531d3ad83SJakub Kicinski 11683c9e13aSJakub Kicinski static void 11783c9e13aSJakub Kicinski nsim_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) 11883c9e13aSJakub Kicinski { 11983c9e13aSJakub Kicinski struct netdevsim *ns = netdev_priv(dev); 12083c9e13aSJakub Kicinski unsigned int start; 12183c9e13aSJakub Kicinski 12283c9e13aSJakub Kicinski do { 12383c9e13aSJakub Kicinski start = u64_stats_fetch_begin(&ns->syncp); 12483c9e13aSJakub Kicinski stats->tx_bytes = ns->tx_bytes; 12583c9e13aSJakub Kicinski stats->tx_packets = ns->tx_packets; 12683c9e13aSJakub Kicinski } while (u64_stats_fetch_retry(&ns->syncp, start)); 12783c9e13aSJakub Kicinski } 12883c9e13aSJakub Kicinski 12931d3ad83SJakub Kicinski static int 13031d3ad83SJakub Kicinski nsim_setup_tc_block_cb(enum tc_setup_type type, void *type_data, void *cb_priv) 13131d3ad83SJakub Kicinski { 13231d3ad83SJakub Kicinski return nsim_bpf_setup_tc_block_cb(type, type_data, cb_priv); 13331d3ad83SJakub Kicinski } 13431d3ad83SJakub Kicinski 13531d3ad83SJakub Kicinski static int 13631d3ad83SJakub Kicinski nsim_setup_tc_block(struct net_device *dev, struct tc_block_offload *f) 13731d3ad83SJakub Kicinski { 13831d3ad83SJakub Kicinski struct netdevsim *ns = netdev_priv(dev); 13931d3ad83SJakub Kicinski 14031d3ad83SJakub Kicinski if (f->binder_type != TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS) 14131d3ad83SJakub Kicinski return -EOPNOTSUPP; 14231d3ad83SJakub Kicinski 14331d3ad83SJakub Kicinski switch (f->command) { 14431d3ad83SJakub Kicinski case TC_BLOCK_BIND: 14531d3ad83SJakub Kicinski return tcf_block_cb_register(f->block, nsim_setup_tc_block_cb, 14660513bd8SJohn Hurley ns, ns, f->extack); 14731d3ad83SJakub Kicinski case TC_BLOCK_UNBIND: 14831d3ad83SJakub Kicinski tcf_block_cb_unregister(f->block, nsim_setup_tc_block_cb, ns); 14931d3ad83SJakub Kicinski return 0; 15031d3ad83SJakub Kicinski default: 15131d3ad83SJakub Kicinski return -EOPNOTSUPP; 15231d3ad83SJakub Kicinski } 15331d3ad83SJakub Kicinski } 15431d3ad83SJakub Kicinski 15579579220SJakub Kicinski static int nsim_set_vf_mac(struct net_device *dev, int vf, u8 *mac) 15679579220SJakub Kicinski { 15779579220SJakub Kicinski struct netdevsim *ns = netdev_priv(dev); 15840e4fe4cSJiri Pirko struct nsim_bus_dev *nsim_bus_dev = ns->nsim_bus_dev; 15979579220SJakub Kicinski 16079579220SJakub Kicinski /* Only refuse multicast addresses, zero address can mean unset/any. */ 16140e4fe4cSJiri Pirko if (vf >= nsim_bus_dev->num_vfs || is_multicast_ether_addr(mac)) 16279579220SJakub Kicinski return -EINVAL; 16340e4fe4cSJiri Pirko memcpy(nsim_bus_dev->vfconfigs[vf].vf_mac, mac, ETH_ALEN); 16479579220SJakub Kicinski 16579579220SJakub Kicinski return 0; 16679579220SJakub Kicinski } 16779579220SJakub Kicinski 16879579220SJakub Kicinski static int nsim_set_vf_vlan(struct net_device *dev, int vf, 16979579220SJakub Kicinski u16 vlan, u8 qos, __be16 vlan_proto) 17079579220SJakub Kicinski { 17179579220SJakub Kicinski struct netdevsim *ns = netdev_priv(dev); 17240e4fe4cSJiri Pirko struct nsim_bus_dev *nsim_bus_dev = ns->nsim_bus_dev; 17379579220SJakub Kicinski 17440e4fe4cSJiri Pirko if (vf >= nsim_bus_dev->num_vfs || vlan > 4095 || qos > 7) 17579579220SJakub Kicinski return -EINVAL; 17679579220SJakub Kicinski 17740e4fe4cSJiri Pirko nsim_bus_dev->vfconfigs[vf].vlan = vlan; 17840e4fe4cSJiri Pirko nsim_bus_dev->vfconfigs[vf].qos = qos; 17940e4fe4cSJiri Pirko nsim_bus_dev->vfconfigs[vf].vlan_proto = vlan_proto; 18079579220SJakub Kicinski 18179579220SJakub Kicinski return 0; 18279579220SJakub Kicinski } 18379579220SJakub Kicinski 18479579220SJakub Kicinski static int nsim_set_vf_rate(struct net_device *dev, int vf, int min, int max) 18579579220SJakub Kicinski { 18679579220SJakub Kicinski struct netdevsim *ns = netdev_priv(dev); 18740e4fe4cSJiri Pirko struct nsim_bus_dev *nsim_bus_dev = ns->nsim_bus_dev; 18879579220SJakub Kicinski 18940e4fe4cSJiri Pirko if (vf >= nsim_bus_dev->num_vfs) 19079579220SJakub Kicinski return -EINVAL; 19179579220SJakub Kicinski 19240e4fe4cSJiri Pirko nsim_bus_dev->vfconfigs[vf].min_tx_rate = min; 19340e4fe4cSJiri Pirko nsim_bus_dev->vfconfigs[vf].max_tx_rate = max; 19479579220SJakub Kicinski 19579579220SJakub Kicinski return 0; 19679579220SJakub Kicinski } 19779579220SJakub Kicinski 19879579220SJakub Kicinski static int nsim_set_vf_spoofchk(struct net_device *dev, int vf, bool val) 19979579220SJakub Kicinski { 20079579220SJakub Kicinski struct netdevsim *ns = netdev_priv(dev); 20140e4fe4cSJiri Pirko struct nsim_bus_dev *nsim_bus_dev = ns->nsim_bus_dev; 20279579220SJakub Kicinski 20340e4fe4cSJiri Pirko if (vf >= nsim_bus_dev->num_vfs) 20479579220SJakub Kicinski return -EINVAL; 20540e4fe4cSJiri Pirko nsim_bus_dev->vfconfigs[vf].spoofchk_enabled = val; 20679579220SJakub Kicinski 20779579220SJakub Kicinski return 0; 20879579220SJakub Kicinski } 20979579220SJakub Kicinski 21079579220SJakub Kicinski static int nsim_set_vf_rss_query_en(struct net_device *dev, int vf, bool val) 21179579220SJakub Kicinski { 21279579220SJakub Kicinski struct netdevsim *ns = netdev_priv(dev); 21340e4fe4cSJiri Pirko struct nsim_bus_dev *nsim_bus_dev = ns->nsim_bus_dev; 21479579220SJakub Kicinski 21540e4fe4cSJiri Pirko if (vf >= nsim_bus_dev->num_vfs) 21679579220SJakub Kicinski return -EINVAL; 21740e4fe4cSJiri Pirko nsim_bus_dev->vfconfigs[vf].rss_query_enabled = val; 21879579220SJakub Kicinski 21979579220SJakub Kicinski return 0; 22079579220SJakub Kicinski } 22179579220SJakub Kicinski 22279579220SJakub Kicinski static int nsim_set_vf_trust(struct net_device *dev, int vf, bool val) 22379579220SJakub Kicinski { 22479579220SJakub Kicinski struct netdevsim *ns = netdev_priv(dev); 22540e4fe4cSJiri Pirko struct nsim_bus_dev *nsim_bus_dev = ns->nsim_bus_dev; 22679579220SJakub Kicinski 22740e4fe4cSJiri Pirko if (vf >= nsim_bus_dev->num_vfs) 22879579220SJakub Kicinski return -EINVAL; 22940e4fe4cSJiri Pirko nsim_bus_dev->vfconfigs[vf].trusted = val; 23079579220SJakub Kicinski 23179579220SJakub Kicinski return 0; 23279579220SJakub Kicinski } 23379579220SJakub Kicinski 23479579220SJakub Kicinski static int 23579579220SJakub Kicinski nsim_get_vf_config(struct net_device *dev, int vf, struct ifla_vf_info *ivi) 23679579220SJakub Kicinski { 23779579220SJakub Kicinski struct netdevsim *ns = netdev_priv(dev); 23840e4fe4cSJiri Pirko struct nsim_bus_dev *nsim_bus_dev = ns->nsim_bus_dev; 23979579220SJakub Kicinski 24040e4fe4cSJiri Pirko if (vf >= nsim_bus_dev->num_vfs) 24179579220SJakub Kicinski return -EINVAL; 24279579220SJakub Kicinski 24379579220SJakub Kicinski ivi->vf = vf; 24440e4fe4cSJiri Pirko ivi->linkstate = nsim_bus_dev->vfconfigs[vf].link_state; 24540e4fe4cSJiri Pirko ivi->min_tx_rate = nsim_bus_dev->vfconfigs[vf].min_tx_rate; 24640e4fe4cSJiri Pirko ivi->max_tx_rate = nsim_bus_dev->vfconfigs[vf].max_tx_rate; 24740e4fe4cSJiri Pirko ivi->vlan = nsim_bus_dev->vfconfigs[vf].vlan; 24840e4fe4cSJiri Pirko ivi->vlan_proto = nsim_bus_dev->vfconfigs[vf].vlan_proto; 24940e4fe4cSJiri Pirko ivi->qos = nsim_bus_dev->vfconfigs[vf].qos; 25040e4fe4cSJiri Pirko memcpy(&ivi->mac, nsim_bus_dev->vfconfigs[vf].vf_mac, ETH_ALEN); 25140e4fe4cSJiri Pirko ivi->spoofchk = nsim_bus_dev->vfconfigs[vf].spoofchk_enabled; 25240e4fe4cSJiri Pirko ivi->trusted = nsim_bus_dev->vfconfigs[vf].trusted; 25340e4fe4cSJiri Pirko ivi->rss_query_en = nsim_bus_dev->vfconfigs[vf].rss_query_enabled; 25479579220SJakub Kicinski 25579579220SJakub Kicinski return 0; 25679579220SJakub Kicinski } 25779579220SJakub Kicinski 25879579220SJakub Kicinski static int nsim_set_vf_link_state(struct net_device *dev, int vf, int state) 25979579220SJakub Kicinski { 26079579220SJakub Kicinski struct netdevsim *ns = netdev_priv(dev); 26140e4fe4cSJiri Pirko struct nsim_bus_dev *nsim_bus_dev = ns->nsim_bus_dev; 26279579220SJakub Kicinski 26340e4fe4cSJiri Pirko if (vf >= nsim_bus_dev->num_vfs) 26479579220SJakub Kicinski return -EINVAL; 26579579220SJakub Kicinski 26679579220SJakub Kicinski switch (state) { 26779579220SJakub Kicinski case IFLA_VF_LINK_STATE_AUTO: 26879579220SJakub Kicinski case IFLA_VF_LINK_STATE_ENABLE: 26979579220SJakub Kicinski case IFLA_VF_LINK_STATE_DISABLE: 27079579220SJakub Kicinski break; 27179579220SJakub Kicinski default: 27279579220SJakub Kicinski return -EINVAL; 27379579220SJakub Kicinski } 27479579220SJakub Kicinski 27540e4fe4cSJiri Pirko nsim_bus_dev->vfconfigs[vf].link_state = state; 27679579220SJakub Kicinski 27779579220SJakub Kicinski return 0; 27879579220SJakub Kicinski } 27979579220SJakub Kicinski 28031d3ad83SJakub Kicinski static int 28131d3ad83SJakub Kicinski nsim_setup_tc(struct net_device *dev, enum tc_setup_type type, void *type_data) 28231d3ad83SJakub Kicinski { 28331d3ad83SJakub Kicinski switch (type) { 28431d3ad83SJakub Kicinski case TC_SETUP_BLOCK: 28531d3ad83SJakub Kicinski return nsim_setup_tc_block(dev, type_data); 28631d3ad83SJakub Kicinski default: 28731d3ad83SJakub Kicinski return -EOPNOTSUPP; 28831d3ad83SJakub Kicinski } 28931d3ad83SJakub Kicinski } 29031d3ad83SJakub Kicinski 29131d3ad83SJakub Kicinski static int 29231d3ad83SJakub Kicinski nsim_set_features(struct net_device *dev, netdev_features_t features) 29331d3ad83SJakub Kicinski { 29431d3ad83SJakub Kicinski struct netdevsim *ns = netdev_priv(dev); 29531d3ad83SJakub Kicinski 29631d3ad83SJakub Kicinski if ((dev->features & NETIF_F_HW_TC) > (features & NETIF_F_HW_TC)) 29731d3ad83SJakub Kicinski return nsim_bpf_disable_tc(ns); 29831d3ad83SJakub Kicinski 29931d3ad83SJakub Kicinski return 0; 30031d3ad83SJakub Kicinski } 30131d3ad83SJakub Kicinski 30283c9e13aSJakub Kicinski static const struct net_device_ops nsim_netdev_ops = { 30331d3ad83SJakub Kicinski .ndo_init = nsim_init, 30431d3ad83SJakub Kicinski .ndo_uninit = nsim_uninit, 30583c9e13aSJakub Kicinski .ndo_start_xmit = nsim_start_xmit, 30683c9e13aSJakub Kicinski .ndo_set_rx_mode = nsim_set_rx_mode, 30783c9e13aSJakub Kicinski .ndo_set_mac_address = eth_mac_addr, 30883c9e13aSJakub Kicinski .ndo_validate_addr = eth_validate_addr, 30931d3ad83SJakub Kicinski .ndo_change_mtu = nsim_change_mtu, 31083c9e13aSJakub Kicinski .ndo_get_stats64 = nsim_get_stats64, 31179579220SJakub Kicinski .ndo_set_vf_mac = nsim_set_vf_mac, 31279579220SJakub Kicinski .ndo_set_vf_vlan = nsim_set_vf_vlan, 31379579220SJakub Kicinski .ndo_set_vf_rate = nsim_set_vf_rate, 31479579220SJakub Kicinski .ndo_set_vf_spoofchk = nsim_set_vf_spoofchk, 31579579220SJakub Kicinski .ndo_set_vf_trust = nsim_set_vf_trust, 31679579220SJakub Kicinski .ndo_get_vf_config = nsim_get_vf_config, 31779579220SJakub Kicinski .ndo_set_vf_link_state = nsim_set_vf_link_state, 31879579220SJakub Kicinski .ndo_set_vf_rss_query_en = nsim_set_vf_rss_query_en, 31931d3ad83SJakub Kicinski .ndo_setup_tc = nsim_setup_tc, 32031d3ad83SJakub Kicinski .ndo_set_features = nsim_set_features, 32131d3ad83SJakub Kicinski .ndo_bpf = nsim_bpf, 322e58df56cSFlorian Fainelli .ndo_get_port_parent_id = nsim_get_port_parent_id, 32383c9e13aSJakub Kicinski }; 32483c9e13aSJakub Kicinski 32583c9e13aSJakub Kicinski static void nsim_setup(struct net_device *dev) 32683c9e13aSJakub Kicinski { 32783c9e13aSJakub Kicinski ether_setup(dev); 32883c9e13aSJakub Kicinski eth_hw_addr_random(dev); 32983c9e13aSJakub Kicinski 33083c9e13aSJakub Kicinski dev->netdev_ops = &nsim_netdev_ops; 331c3d9a435SJiri Pirko dev->needs_free_netdev = true; 33279579220SJakub Kicinski dev->priv_destructor = nsim_free; 33383c9e13aSJakub Kicinski 33483c9e13aSJakub Kicinski dev->tx_queue_len = 0; 33583c9e13aSJakub Kicinski dev->flags |= IFF_NOARP; 33683c9e13aSJakub Kicinski dev->flags &= ~IFF_MULTICAST; 33783c9e13aSJakub Kicinski dev->priv_flags |= IFF_LIVE_ADDR_CHANGE | 33883c9e13aSJakub Kicinski IFF_NO_QUEUE; 33983c9e13aSJakub Kicinski dev->features |= NETIF_F_HIGHDMA | 34083c9e13aSJakub Kicinski NETIF_F_SG | 34183c9e13aSJakub Kicinski NETIF_F_FRAGLIST | 34283c9e13aSJakub Kicinski NETIF_F_HW_CSUM | 34383c9e13aSJakub Kicinski NETIF_F_TSO; 34431d3ad83SJakub Kicinski dev->hw_features |= NETIF_F_HW_TC; 34583c9e13aSJakub Kicinski dev->max_mtu = ETH_MAX_MTU; 34683c9e13aSJakub Kicinski } 34783c9e13aSJakub Kicinski 34883c9e13aSJakub Kicinski static int nsim_validate(struct nlattr *tb[], struct nlattr *data[], 34983c9e13aSJakub Kicinski struct netlink_ext_ack *extack) 35083c9e13aSJakub Kicinski { 35183c9e13aSJakub Kicinski if (tb[IFLA_ADDRESS]) { 35283c9e13aSJakub Kicinski if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN) 35383c9e13aSJakub Kicinski return -EINVAL; 35483c9e13aSJakub Kicinski if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS]))) 35583c9e13aSJakub Kicinski return -EADDRNOTAVAIL; 35683c9e13aSJakub Kicinski } 35783c9e13aSJakub Kicinski return 0; 35883c9e13aSJakub Kicinski } 35983c9e13aSJakub Kicinski 360eeeaaf18SJakub Kicinski static int nsim_newlink(struct net *src_net, struct net_device *dev, 361eeeaaf18SJakub Kicinski struct nlattr *tb[], struct nlattr *data[], 362eeeaaf18SJakub Kicinski struct netlink_ext_ack *extack) 363eeeaaf18SJakub Kicinski { 364eeeaaf18SJakub Kicinski struct netdevsim *ns = netdev_priv(dev); 365af9095f0SJiri Pirko int err; 366eeeaaf18SJakub Kicinski 367f9d9db47SJiri Pirko ns->nsim_bus_dev = nsim_bus_dev_new(~0, 0); 368d514f41eSJiri Pirko if (IS_ERR(ns->nsim_bus_dev)) 369d514f41eSJiri Pirko return PTR_ERR(ns->nsim_bus_dev); 3701daf36c0SJiri Pirko 37140e4fe4cSJiri Pirko SET_NETDEV_DEV(dev, &ns->nsim_bus_dev->dev); 3725fc49422SJiri Pirko ns->netdev = dev; 3735fc49422SJiri Pirko 374a60f9e48SJiri Pirko ns->nsim_dev = nsim_dev_create_with_ns(ns->nsim_bus_dev, ns); 375a60f9e48SJiri Pirko if (IS_ERR(ns->nsim_dev)) { 376a60f9e48SJiri Pirko err = PTR_ERR(ns->nsim_dev); 37740e4fe4cSJiri Pirko goto err_dev_del; 378a60f9e48SJiri Pirko } 3791daf36c0SJiri Pirko 3801daf36c0SJiri Pirko err = register_netdevice(dev); 3811daf36c0SJiri Pirko if (err) 382a60f9e48SJiri Pirko goto err_dev_destroy; 383af9095f0SJiri Pirko return 0; 384af9095f0SJiri Pirko 385a60f9e48SJiri Pirko err_dev_destroy: 386a60f9e48SJiri Pirko nsim_dev_destroy(ns->nsim_dev); 38740e4fe4cSJiri Pirko err_dev_del: 38840e4fe4cSJiri Pirko nsim_bus_dev_del(ns->nsim_bus_dev); 389af9095f0SJiri Pirko return err; 390eeeaaf18SJakub Kicinski } 391eeeaaf18SJakub Kicinski 39283c9e13aSJakub Kicinski static struct rtnl_link_ops nsim_link_ops __read_mostly = { 39383c9e13aSJakub Kicinski .kind = DRV_NAME, 39483c9e13aSJakub Kicinski .priv_size = sizeof(struct netdevsim), 39583c9e13aSJakub Kicinski .setup = nsim_setup, 39683c9e13aSJakub Kicinski .validate = nsim_validate, 397eeeaaf18SJakub Kicinski .newlink = nsim_newlink, 39883c9e13aSJakub Kicinski }; 39983c9e13aSJakub Kicinski 40083c9e13aSJakub Kicinski static int __init nsim_module_init(void) 40183c9e13aSJakub Kicinski { 40231d3ad83SJakub Kicinski int err; 40331d3ad83SJakub Kicinski 404d514f41eSJiri Pirko err = nsim_dev_init(); 405af9095f0SJiri Pirko if (err) 406*ab1d0cc0SJiri Pirko return err; 407eeeaaf18SJakub Kicinski 408925f5afeSJiri Pirko err = nsim_bus_init(); 40931d3ad83SJakub Kicinski if (err) 410d514f41eSJiri Pirko goto err_dev_exit; 41131d3ad83SJakub Kicinski 4125fc49422SJiri Pirko err = rtnl_link_register(&nsim_link_ops); 41379579220SJakub Kicinski if (err) 414925f5afeSJiri Pirko goto err_bus_exit; 41579579220SJakub Kicinski 41631d3ad83SJakub Kicinski return 0; 41731d3ad83SJakub Kicinski 418925f5afeSJiri Pirko err_bus_exit: 419925f5afeSJiri Pirko nsim_bus_exit(); 420d514f41eSJiri Pirko err_dev_exit: 421d514f41eSJiri Pirko nsim_dev_exit(); 42231d3ad83SJakub Kicinski return err; 42383c9e13aSJakub Kicinski } 42483c9e13aSJakub Kicinski 42583c9e13aSJakub Kicinski static void __exit nsim_module_exit(void) 42683c9e13aSJakub Kicinski { 42783c9e13aSJakub Kicinski rtnl_link_unregister(&nsim_link_ops); 428925f5afeSJiri Pirko nsim_bus_exit(); 429d514f41eSJiri Pirko nsim_dev_exit(); 43083c9e13aSJakub Kicinski } 43183c9e13aSJakub Kicinski 43283c9e13aSJakub Kicinski module_init(nsim_module_init); 43383c9e13aSJakub Kicinski module_exit(nsim_module_exit); 43483c9e13aSJakub Kicinski MODULE_LICENSE("GPL"); 43583c9e13aSJakub Kicinski MODULE_ALIAS_RTNL_LINK(DRV_NAME); 436