18fb4bc6fSJiri Pirko /* 28fb4bc6fSJiri Pirko * Copyright (c) 2018 Cumulus Networks. All rights reserved. 38fb4bc6fSJiri Pirko * Copyright (c) 2018 David Ahern <[email protected]> 48fb4bc6fSJiri Pirko * Copyright (c) 2019 Mellanox Technologies. All rights reserved. 58fb4bc6fSJiri Pirko * 68fb4bc6fSJiri Pirko * This software is licensed under the GNU General License Version 2, 78fb4bc6fSJiri Pirko * June 1991 as shown in the file COPYING in the top-level directory of this 88fb4bc6fSJiri Pirko * source tree. 98fb4bc6fSJiri Pirko * 108fb4bc6fSJiri Pirko * THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" 118fb4bc6fSJiri Pirko * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, 128fb4bc6fSJiri Pirko * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 138fb4bc6fSJiri Pirko * FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE 148fb4bc6fSJiri Pirko * OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME 158fb4bc6fSJiri Pirko * THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 168fb4bc6fSJiri Pirko */ 178fb4bc6fSJiri Pirko 18d514f41eSJiri Pirko #include <linux/debugfs.h> 198fb4bc6fSJiri Pirko #include <linux/device.h> 20da58f90fSIdo Schimmel #include <linux/etherdevice.h> 21da58f90fSIdo Schimmel #include <linux/inet.h> 22da58f90fSIdo Schimmel #include <linux/jiffies.h> 23da58f90fSIdo Schimmel #include <linux/kernel.h> 248320d145SJiri Pirko #include <linux/list.h> 25794b2c05SJiri Pirko #include <linux/mutex.h> 26514cf64cSJiri Pirko #include <linux/random.h> 278fb4bc6fSJiri Pirko #include <linux/rtnetlink.h> 28da58f90fSIdo Schimmel #include <linux/workqueue.h> 298fb4bc6fSJiri Pirko #include <net/devlink.h> 30da58f90fSIdo Schimmel #include <net/ip.h> 31d3cbb907SJiri Pirko #include <net/flow_offload.h> 32da58f90fSIdo Schimmel #include <uapi/linux/devlink.h> 33da58f90fSIdo Schimmel #include <uapi/linux/ip.h> 34da58f90fSIdo Schimmel #include <uapi/linux/udp.h> 358fb4bc6fSJiri Pirko 368fb4bc6fSJiri Pirko #include "netdevsim.h" 378fb4bc6fSJiri Pirko 38814b9ce6SDmytro Linkin static unsigned int 39814b9ce6SDmytro Linkin nsim_dev_port_index(enum nsim_dev_port_type type, unsigned int port_index) 40814b9ce6SDmytro Linkin { 41814b9ce6SDmytro Linkin switch (type) { 42814b9ce6SDmytro Linkin case NSIM_DEV_PORT_TYPE_VF: 43814b9ce6SDmytro Linkin port_index = NSIM_DEV_VF_PORT_INDEX_BASE + port_index; 44814b9ce6SDmytro Linkin break; 45814b9ce6SDmytro Linkin case NSIM_DEV_PORT_TYPE_PF: 46814b9ce6SDmytro Linkin break; 47814b9ce6SDmytro Linkin } 48814b9ce6SDmytro Linkin 49814b9ce6SDmytro Linkin return port_index; 50814b9ce6SDmytro Linkin } 51814b9ce6SDmytro Linkin 52814b9ce6SDmytro Linkin static inline unsigned int nsim_dev_port_index_to_vf_index(unsigned int port_index) 53814b9ce6SDmytro Linkin { 54814b9ce6SDmytro Linkin return port_index - NSIM_DEV_VF_PORT_INDEX_BASE; 55814b9ce6SDmytro Linkin } 56814b9ce6SDmytro Linkin 57d514f41eSJiri Pirko static struct dentry *nsim_dev_ddir; 58d514f41eSJiri Pirko 594418f862SJiri Pirko #define NSIM_DEV_DUMMY_REGION_SIZE (1024 * 32) 604418f862SJiri Pirko 613fe0fd53SJacob Keller static int 62d4602a9fSAndrew Lunn nsim_dev_take_snapshot(struct devlink *devlink, 63d4602a9fSAndrew Lunn const struct devlink_region_ops *ops, 64d4602a9fSAndrew Lunn struct netlink_ext_ack *extack, 653fe0fd53SJacob Keller u8 **data) 664418f862SJiri Pirko { 674418f862SJiri Pirko void *dummy_data; 6812102436SJacob Keller 694418f862SJiri Pirko dummy_data = kmalloc(NSIM_DEV_DUMMY_REGION_SIZE, GFP_KERNEL); 704418f862SJiri Pirko if (!dummy_data) 714418f862SJiri Pirko return -ENOMEM; 724418f862SJiri Pirko 734418f862SJiri Pirko get_random_bytes(dummy_data, NSIM_DEV_DUMMY_REGION_SIZE); 744418f862SJiri Pirko 753fe0fd53SJacob Keller *data = dummy_data; 763fe0fd53SJacob Keller 773fe0fd53SJacob Keller return 0; 783fe0fd53SJacob Keller } 793fe0fd53SJacob Keller 803fe0fd53SJacob Keller static ssize_t nsim_dev_take_snapshot_write(struct file *file, 813fe0fd53SJacob Keller const char __user *data, 823fe0fd53SJacob Keller size_t count, loff_t *ppos) 833fe0fd53SJacob Keller { 843fe0fd53SJacob Keller struct nsim_dev *nsim_dev = file->private_data; 853fe0fd53SJacob Keller struct devlink *devlink; 863fe0fd53SJacob Keller u8 *dummy_data; 873fe0fd53SJacob Keller int err; 883fe0fd53SJacob Keller u32 id; 893fe0fd53SJacob Keller 903fe0fd53SJacob Keller devlink = priv_to_devlink(nsim_dev); 913fe0fd53SJacob Keller 92d4602a9fSAndrew Lunn err = nsim_dev_take_snapshot(devlink, NULL, NULL, &dummy_data); 933fe0fd53SJacob Keller if (err) 943fe0fd53SJacob Keller return err; 953fe0fd53SJacob Keller 9612102436SJacob Keller err = devlink_region_snapshot_id_get(devlink, &id); 977ef19d3bSJacob Keller if (err) { 987ef19d3bSJacob Keller pr_err("Failed to get snapshot id\n"); 993902baf9SGustavo A. R. Silva kfree(dummy_data); 1007ef19d3bSJacob Keller return err; 1017ef19d3bSJacob Keller } 1024418f862SJiri Pirko err = devlink_region_snapshot_create(nsim_dev->dummy_region, 103a0a09f6bSJacob Keller dummy_data, id); 10412102436SJacob Keller devlink_region_snapshot_id_put(devlink, id); 1054418f862SJiri Pirko if (err) { 1064418f862SJiri Pirko pr_err("Failed to create region snapshot\n"); 1074418f862SJiri Pirko kfree(dummy_data); 1084418f862SJiri Pirko return err; 1094418f862SJiri Pirko } 1104418f862SJiri Pirko 1114418f862SJiri Pirko return count; 1124418f862SJiri Pirko } 1134418f862SJiri Pirko 1144418f862SJiri Pirko static const struct file_operations nsim_dev_take_snapshot_fops = { 1154418f862SJiri Pirko .open = simple_open, 1164418f862SJiri Pirko .write = nsim_dev_take_snapshot_write, 1174418f862SJiri Pirko .llseek = generic_file_llseek, 118a5bbcbf2STaehee Yoo .owner = THIS_MODULE, 1194418f862SJiri Pirko }; 1204418f862SJiri Pirko 121d3cbb907SJiri Pirko static ssize_t nsim_dev_trap_fa_cookie_read(struct file *file, 122d3cbb907SJiri Pirko char __user *data, 123d3cbb907SJiri Pirko size_t count, loff_t *ppos) 124d3cbb907SJiri Pirko { 125d3cbb907SJiri Pirko struct nsim_dev *nsim_dev = file->private_data; 126d3cbb907SJiri Pirko struct flow_action_cookie *fa_cookie; 127d3cbb907SJiri Pirko unsigned int buf_len; 128d3cbb907SJiri Pirko ssize_t ret; 129d3cbb907SJiri Pirko char *buf; 130d3cbb907SJiri Pirko 131d3cbb907SJiri Pirko spin_lock(&nsim_dev->fa_cookie_lock); 132d3cbb907SJiri Pirko fa_cookie = nsim_dev->fa_cookie; 133d3cbb907SJiri Pirko if (!fa_cookie) { 134d3cbb907SJiri Pirko ret = -EINVAL; 135d3cbb907SJiri Pirko goto errout; 136d3cbb907SJiri Pirko } 137d3cbb907SJiri Pirko buf_len = fa_cookie->cookie_len * 2; 138d3cbb907SJiri Pirko buf = kmalloc(buf_len, GFP_ATOMIC); 139d3cbb907SJiri Pirko if (!buf) { 140d3cbb907SJiri Pirko ret = -ENOMEM; 141d3cbb907SJiri Pirko goto errout; 142d3cbb907SJiri Pirko } 143d3cbb907SJiri Pirko bin2hex(buf, fa_cookie->cookie, fa_cookie->cookie_len); 144d3cbb907SJiri Pirko spin_unlock(&nsim_dev->fa_cookie_lock); 145d3cbb907SJiri Pirko 146d3cbb907SJiri Pirko ret = simple_read_from_buffer(data, count, ppos, buf, buf_len); 147d3cbb907SJiri Pirko 148d3cbb907SJiri Pirko kfree(buf); 149d3cbb907SJiri Pirko return ret; 150d3cbb907SJiri Pirko 151d3cbb907SJiri Pirko errout: 152d3cbb907SJiri Pirko spin_unlock(&nsim_dev->fa_cookie_lock); 153d3cbb907SJiri Pirko return ret; 154d3cbb907SJiri Pirko } 155d3cbb907SJiri Pirko 156d3cbb907SJiri Pirko static ssize_t nsim_dev_trap_fa_cookie_write(struct file *file, 157d3cbb907SJiri Pirko const char __user *data, 158d3cbb907SJiri Pirko size_t count, loff_t *ppos) 159d3cbb907SJiri Pirko { 160d3cbb907SJiri Pirko struct nsim_dev *nsim_dev = file->private_data; 161d3cbb907SJiri Pirko struct flow_action_cookie *fa_cookie; 162d3cbb907SJiri Pirko size_t cookie_len; 163d3cbb907SJiri Pirko ssize_t ret; 164d3cbb907SJiri Pirko char *buf; 165d3cbb907SJiri Pirko 166d3cbb907SJiri Pirko if (*ppos != 0) 167d3cbb907SJiri Pirko return -EINVAL; 168d3cbb907SJiri Pirko cookie_len = (count - 1) / 2; 169d3cbb907SJiri Pirko if ((count - 1) % 2) 170d3cbb907SJiri Pirko return -EINVAL; 171d3cbb907SJiri Pirko buf = kmalloc(count, GFP_KERNEL | __GFP_NOWARN); 172d3cbb907SJiri Pirko if (!buf) 173d3cbb907SJiri Pirko return -ENOMEM; 174d3cbb907SJiri Pirko 175d3cbb907SJiri Pirko ret = simple_write_to_buffer(buf, count, ppos, data, count); 176d3cbb907SJiri Pirko if (ret < 0) 177d3cbb907SJiri Pirko goto free_buf; 178d3cbb907SJiri Pirko 179d3cbb907SJiri Pirko fa_cookie = kmalloc(sizeof(*fa_cookie) + cookie_len, 180d3cbb907SJiri Pirko GFP_KERNEL | __GFP_NOWARN); 181d3cbb907SJiri Pirko if (!fa_cookie) { 182d3cbb907SJiri Pirko ret = -ENOMEM; 183d3cbb907SJiri Pirko goto free_buf; 184d3cbb907SJiri Pirko } 185d3cbb907SJiri Pirko 186d3cbb907SJiri Pirko fa_cookie->cookie_len = cookie_len; 187d3cbb907SJiri Pirko ret = hex2bin(fa_cookie->cookie, buf, cookie_len); 188d3cbb907SJiri Pirko if (ret) 189d3cbb907SJiri Pirko goto free_fa_cookie; 190d3cbb907SJiri Pirko kfree(buf); 191d3cbb907SJiri Pirko 192d3cbb907SJiri Pirko spin_lock(&nsim_dev->fa_cookie_lock); 193d3cbb907SJiri Pirko kfree(nsim_dev->fa_cookie); 194d3cbb907SJiri Pirko nsim_dev->fa_cookie = fa_cookie; 195d3cbb907SJiri Pirko spin_unlock(&nsim_dev->fa_cookie_lock); 196d3cbb907SJiri Pirko 197d3cbb907SJiri Pirko return count; 198d3cbb907SJiri Pirko 199d3cbb907SJiri Pirko free_fa_cookie: 200d3cbb907SJiri Pirko kfree(fa_cookie); 201d3cbb907SJiri Pirko free_buf: 202d3cbb907SJiri Pirko kfree(buf); 203d3cbb907SJiri Pirko return ret; 204d3cbb907SJiri Pirko } 205d3cbb907SJiri Pirko 206d3cbb907SJiri Pirko static const struct file_operations nsim_dev_trap_fa_cookie_fops = { 207d3cbb907SJiri Pirko .open = simple_open, 208d3cbb907SJiri Pirko .read = nsim_dev_trap_fa_cookie_read, 209d3cbb907SJiri Pirko .write = nsim_dev_trap_fa_cookie_write, 210d3cbb907SJiri Pirko .llseek = generic_file_llseek, 211a5bbcbf2STaehee Yoo .owner = THIS_MODULE, 212d3cbb907SJiri Pirko }; 213d3cbb907SJiri Pirko 214d3953819SDmytro Linkin static const struct file_operations nsim_dev_max_vfs_fops = { 215d3953819SDmytro Linkin .open = simple_open, 216d3953819SDmytro Linkin .read = nsim_bus_dev_max_vfs_read, 217d3953819SDmytro Linkin .write = nsim_bus_dev_max_vfs_write, 218d3953819SDmytro Linkin .llseek = generic_file_llseek, 219d3953819SDmytro Linkin .owner = THIS_MODULE, 220d3953819SDmytro Linkin }; 221d3953819SDmytro Linkin 222d514f41eSJiri Pirko static int nsim_dev_debugfs_init(struct nsim_dev *nsim_dev) 223d514f41eSJiri Pirko { 2246fb8852bSTaehee Yoo char dev_ddir_name[sizeof(DRV_NAME) + 10]; 225f3d101b4SDmytro Linkin int err; 226d514f41eSJiri Pirko 227ab1d0cc0SJiri Pirko sprintf(dev_ddir_name, DRV_NAME "%u", nsim_dev->nsim_bus_dev->dev.id); 228d514f41eSJiri Pirko nsim_dev->ddir = debugfs_create_dir(dev_ddir_name, nsim_dev_ddir); 2296556ff32STaehee Yoo if (IS_ERR(nsim_dev->ddir)) 2306556ff32STaehee Yoo return PTR_ERR(nsim_dev->ddir); 231ab1d0cc0SJiri Pirko nsim_dev->ports_ddir = debugfs_create_dir("ports", nsim_dev->ddir); 2326556ff32STaehee Yoo if (IS_ERR(nsim_dev->ports_ddir)) 2336556ff32STaehee Yoo return PTR_ERR(nsim_dev->ports_ddir); 234fa4dfc4aSJiri Pirko debugfs_create_bool("fw_update_status", 0600, nsim_dev->ddir, 235fa4dfc4aSJiri Pirko &nsim_dev->fw_update_status); 236cbb58368SJacob Keller debugfs_create_u32("fw_update_overwrite_mask", 0600, nsim_dev->ddir, 237cbb58368SJacob Keller &nsim_dev->fw_update_overwrite_mask); 238150e8f8aSJiri Pirko debugfs_create_u32("max_macs", 0600, nsim_dev->ddir, 239150e8f8aSJiri Pirko &nsim_dev->max_macs); 240150e8f8aSJiri Pirko debugfs_create_bool("test1", 0600, nsim_dev->ddir, 241150e8f8aSJiri Pirko &nsim_dev->test1); 2428526ad96STaehee Yoo nsim_dev->take_snapshot = debugfs_create_file("take_snapshot", 2438526ad96STaehee Yoo 0200, 2448526ad96STaehee Yoo nsim_dev->ddir, 2458526ad96STaehee Yoo nsim_dev, 2464418f862SJiri Pirko &nsim_dev_take_snapshot_fops); 247155ddfc5SJiri Pirko debugfs_create_bool("dont_allow_reload", 0600, nsim_dev->ddir, 248155ddfc5SJiri Pirko &nsim_dev->dont_allow_reload); 249155ddfc5SJiri Pirko debugfs_create_bool("fail_reload", 0600, nsim_dev->ddir, 250155ddfc5SJiri Pirko &nsim_dev->fail_reload); 251d3cbb907SJiri Pirko debugfs_create_file("trap_flow_action_cookie", 0600, nsim_dev->ddir, 252d3cbb907SJiri Pirko nsim_dev, &nsim_dev_trap_fa_cookie_fops); 2530dc8249aSIdo Schimmel debugfs_create_bool("fail_trap_group_set", 0600, 2540dc8249aSIdo Schimmel nsim_dev->ddir, 2550dc8249aSIdo Schimmel &nsim_dev->fail_trap_group_set); 256ad188458SIdo Schimmel debugfs_create_bool("fail_trap_policer_set", 0600, 257ad188458SIdo Schimmel nsim_dev->ddir, 258ad188458SIdo Schimmel &nsim_dev->fail_trap_policer_set); 259ad188458SIdo Schimmel debugfs_create_bool("fail_trap_policer_counter_get", 0600, 260ad188458SIdo Schimmel nsim_dev->ddir, 261ad188458SIdo Schimmel &nsim_dev->fail_trap_policer_counter_get); 262d3953819SDmytro Linkin nsim_dev->max_vfs = debugfs_create_file("max_vfs", 263d3953819SDmytro Linkin 0600, 264d3953819SDmytro Linkin nsim_dev->ddir, 265d3953819SDmytro Linkin nsim_dev->nsim_bus_dev, 266d3953819SDmytro Linkin &nsim_dev_max_vfs_fops); 267885226f5SDmytro Linkin nsim_dev->nodes_ddir = debugfs_create_dir("rate_nodes", nsim_dev->ddir); 268f3d101b4SDmytro Linkin if (IS_ERR(nsim_dev->nodes_ddir)) { 269f3d101b4SDmytro Linkin err = PTR_ERR(nsim_dev->nodes_ddir); 270f3d101b4SDmytro Linkin goto err_out; 271f3d101b4SDmytro Linkin } 272424be63aSJakub Kicinski nsim_udp_tunnels_debugfs_create(nsim_dev); 273d514f41eSJiri Pirko return 0; 274f3d101b4SDmytro Linkin 275f3d101b4SDmytro Linkin err_out: 276f3d101b4SDmytro Linkin debugfs_remove_recursive(nsim_dev->ports_ddir); 277f3d101b4SDmytro Linkin debugfs_remove_recursive(nsim_dev->ddir); 278f3d101b4SDmytro Linkin return err; 279d514f41eSJiri Pirko } 280d514f41eSJiri Pirko 281d514f41eSJiri Pirko static void nsim_dev_debugfs_exit(struct nsim_dev *nsim_dev) 282d514f41eSJiri Pirko { 283885226f5SDmytro Linkin debugfs_remove_recursive(nsim_dev->nodes_ddir); 284ab1d0cc0SJiri Pirko debugfs_remove_recursive(nsim_dev->ports_ddir); 285d514f41eSJiri Pirko debugfs_remove_recursive(nsim_dev->ddir); 286d514f41eSJiri Pirko } 287d514f41eSJiri Pirko 288f3d101b4SDmytro Linkin static ssize_t nsim_dev_rate_parent_read(struct file *file, 289f3d101b4SDmytro Linkin char __user *data, 290f3d101b4SDmytro Linkin size_t count, loff_t *ppos) 291f3d101b4SDmytro Linkin { 292f3d101b4SDmytro Linkin char **name_ptr = file->private_data; 293f3d101b4SDmytro Linkin size_t len; 294f3d101b4SDmytro Linkin 295f3d101b4SDmytro Linkin if (!*name_ptr) 296f3d101b4SDmytro Linkin return 0; 297f3d101b4SDmytro Linkin 298f3d101b4SDmytro Linkin len = strlen(*name_ptr); 299f3d101b4SDmytro Linkin return simple_read_from_buffer(data, count, ppos, *name_ptr, len); 300f3d101b4SDmytro Linkin } 301f3d101b4SDmytro Linkin 302f3d101b4SDmytro Linkin static const struct file_operations nsim_dev_rate_parent_fops = { 303f3d101b4SDmytro Linkin .open = simple_open, 304f3d101b4SDmytro Linkin .read = nsim_dev_rate_parent_read, 305f3d101b4SDmytro Linkin .llseek = generic_file_llseek, 306f3d101b4SDmytro Linkin .owner = THIS_MODULE, 307f3d101b4SDmytro Linkin }; 308f3d101b4SDmytro Linkin 3098320d145SJiri Pirko static int nsim_dev_port_debugfs_init(struct nsim_dev *nsim_dev, 3108320d145SJiri Pirko struct nsim_dev_port *nsim_dev_port) 3118320d145SJiri Pirko { 312605c4f8fSDmytro Linkin struct nsim_bus_dev *nsim_bus_dev = nsim_dev->nsim_bus_dev; 313605c4f8fSDmytro Linkin unsigned int port_index = nsim_dev_port->port_index; 3148320d145SJiri Pirko char port_ddir_name[16]; 3158320d145SJiri Pirko char dev_link_name[32]; 3168320d145SJiri Pirko 317605c4f8fSDmytro Linkin sprintf(port_ddir_name, "%u", port_index); 3188320d145SJiri Pirko nsim_dev_port->ddir = debugfs_create_dir(port_ddir_name, 3198320d145SJiri Pirko nsim_dev->ports_ddir); 3206556ff32STaehee Yoo if (IS_ERR(nsim_dev_port->ddir)) 3216556ff32STaehee Yoo return PTR_ERR(nsim_dev_port->ddir); 3228320d145SJiri Pirko 323605c4f8fSDmytro Linkin sprintf(dev_link_name, "../../../" DRV_NAME "%u", nsim_bus_dev->dev.id); 324605c4f8fSDmytro Linkin if (nsim_dev_port_is_vf(nsim_dev_port)) { 325605c4f8fSDmytro Linkin unsigned int vf_id = nsim_dev_port_index_to_vf_index(port_index); 326605c4f8fSDmytro Linkin 327605c4f8fSDmytro Linkin debugfs_create_u16("tx_share", 0400, nsim_dev_port->ddir, 328605c4f8fSDmytro Linkin &nsim_bus_dev->vfconfigs[vf_id].min_tx_rate); 329605c4f8fSDmytro Linkin debugfs_create_u16("tx_max", 0400, nsim_dev_port->ddir, 330605c4f8fSDmytro Linkin &nsim_bus_dev->vfconfigs[vf_id].max_tx_rate); 331f3d101b4SDmytro Linkin nsim_dev_port->rate_parent = debugfs_create_file("rate_parent", 332f3d101b4SDmytro Linkin 0400, 333f3d101b4SDmytro Linkin nsim_dev_port->ddir, 334f3d101b4SDmytro Linkin &nsim_dev_port->parent_name, 335f3d101b4SDmytro Linkin &nsim_dev_rate_parent_fops); 336605c4f8fSDmytro Linkin } 3378320d145SJiri Pirko debugfs_create_symlink("dev", nsim_dev_port->ddir, dev_link_name); 3388320d145SJiri Pirko 3398320d145SJiri Pirko return 0; 3408320d145SJiri Pirko } 3418320d145SJiri Pirko 3428320d145SJiri Pirko static void nsim_dev_port_debugfs_exit(struct nsim_dev_port *nsim_dev_port) 3438320d145SJiri Pirko { 3448320d145SJiri Pirko debugfs_remove_recursive(nsim_dev_port->ddir); 3458320d145SJiri Pirko } 3468320d145SJiri Pirko 3478fb4bc6fSJiri Pirko static int nsim_dev_resources_register(struct devlink *devlink) 3488fb4bc6fSJiri Pirko { 3498fb4bc6fSJiri Pirko struct devlink_resource_size_params params = { 3508fb4bc6fSJiri Pirko .size_max = (u64)-1, 3518fb4bc6fSJiri Pirko .size_granularity = 1, 3528fb4bc6fSJiri Pirko .unit = DEVLINK_RESOURCE_UNIT_ENTRY 3538fb4bc6fSJiri Pirko }; 3548fb4bc6fSJiri Pirko int err; 3558fb4bc6fSJiri Pirko 3568fb4bc6fSJiri Pirko /* Resources for IPv4 */ 3578fb4bc6fSJiri Pirko err = devlink_resource_register(devlink, "IPv4", (u64)-1, 3588fb4bc6fSJiri Pirko NSIM_RESOURCE_IPV4, 3598fb4bc6fSJiri Pirko DEVLINK_RESOURCE_ID_PARENT_TOP, 3608fb4bc6fSJiri Pirko ¶ms); 3618fb4bc6fSJiri Pirko if (err) { 3628fb4bc6fSJiri Pirko pr_err("Failed to register IPv4 top resource\n"); 3638fb4bc6fSJiri Pirko goto out; 3648fb4bc6fSJiri Pirko } 3658fb4bc6fSJiri Pirko 366a5facc4cSJiri Pirko err = devlink_resource_register(devlink, "fib", (u64)-1, 3678fb4bc6fSJiri Pirko NSIM_RESOURCE_IPV4_FIB, 3688fb4bc6fSJiri Pirko NSIM_RESOURCE_IPV4, ¶ms); 3698fb4bc6fSJiri Pirko if (err) { 3708fb4bc6fSJiri Pirko pr_err("Failed to register IPv4 FIB resource\n"); 3718fb4bc6fSJiri Pirko return err; 3728fb4bc6fSJiri Pirko } 3738fb4bc6fSJiri Pirko 374a5facc4cSJiri Pirko err = devlink_resource_register(devlink, "fib-rules", (u64)-1, 3758fb4bc6fSJiri Pirko NSIM_RESOURCE_IPV4_FIB_RULES, 3768fb4bc6fSJiri Pirko NSIM_RESOURCE_IPV4, ¶ms); 3778fb4bc6fSJiri Pirko if (err) { 3788fb4bc6fSJiri Pirko pr_err("Failed to register IPv4 FIB rules resource\n"); 3798fb4bc6fSJiri Pirko return err; 3808fb4bc6fSJiri Pirko } 3818fb4bc6fSJiri Pirko 3828fb4bc6fSJiri Pirko /* Resources for IPv6 */ 3838fb4bc6fSJiri Pirko err = devlink_resource_register(devlink, "IPv6", (u64)-1, 3848fb4bc6fSJiri Pirko NSIM_RESOURCE_IPV6, 3858fb4bc6fSJiri Pirko DEVLINK_RESOURCE_ID_PARENT_TOP, 3868fb4bc6fSJiri Pirko ¶ms); 3878fb4bc6fSJiri Pirko if (err) { 3888fb4bc6fSJiri Pirko pr_err("Failed to register IPv6 top resource\n"); 3898fb4bc6fSJiri Pirko goto out; 3908fb4bc6fSJiri Pirko } 3918fb4bc6fSJiri Pirko 392a5facc4cSJiri Pirko err = devlink_resource_register(devlink, "fib", (u64)-1, 3938fb4bc6fSJiri Pirko NSIM_RESOURCE_IPV6_FIB, 3948fb4bc6fSJiri Pirko NSIM_RESOURCE_IPV6, ¶ms); 3958fb4bc6fSJiri Pirko if (err) { 3968fb4bc6fSJiri Pirko pr_err("Failed to register IPv6 FIB resource\n"); 3978fb4bc6fSJiri Pirko return err; 3988fb4bc6fSJiri Pirko } 3998fb4bc6fSJiri Pirko 400a5facc4cSJiri Pirko err = devlink_resource_register(devlink, "fib-rules", (u64)-1, 4018fb4bc6fSJiri Pirko NSIM_RESOURCE_IPV6_FIB_RULES, 4028fb4bc6fSJiri Pirko NSIM_RESOURCE_IPV6, ¶ms); 4038fb4bc6fSJiri Pirko if (err) { 4048fb4bc6fSJiri Pirko pr_err("Failed to register IPv6 FIB rules resource\n"); 4058fb4bc6fSJiri Pirko return err; 4068fb4bc6fSJiri Pirko } 4078fb4bc6fSJiri Pirko 40835266255SIdo Schimmel /* Resources for nexthops */ 40935266255SIdo Schimmel err = devlink_resource_register(devlink, "nexthops", (u64)-1, 41035266255SIdo Schimmel NSIM_RESOURCE_NEXTHOPS, 41135266255SIdo Schimmel DEVLINK_RESOURCE_ID_PARENT_TOP, 41235266255SIdo Schimmel ¶ms); 41335266255SIdo Schimmel 4148fb4bc6fSJiri Pirko out: 4158fb4bc6fSJiri Pirko return err; 4168fb4bc6fSJiri Pirko } 4178fb4bc6fSJiri Pirko 418150e8f8aSJiri Pirko enum nsim_devlink_param_id { 419150e8f8aSJiri Pirko NSIM_DEVLINK_PARAM_ID_BASE = DEVLINK_PARAM_GENERIC_ID_MAX, 420150e8f8aSJiri Pirko NSIM_DEVLINK_PARAM_ID_TEST1, 421150e8f8aSJiri Pirko }; 422150e8f8aSJiri Pirko 423150e8f8aSJiri Pirko static const struct devlink_param nsim_devlink_params[] = { 424150e8f8aSJiri Pirko DEVLINK_PARAM_GENERIC(MAX_MACS, 425150e8f8aSJiri Pirko BIT(DEVLINK_PARAM_CMODE_DRIVERINIT), 426150e8f8aSJiri Pirko NULL, NULL, NULL), 427150e8f8aSJiri Pirko DEVLINK_PARAM_DRIVER(NSIM_DEVLINK_PARAM_ID_TEST1, 428150e8f8aSJiri Pirko "test1", DEVLINK_PARAM_TYPE_BOOL, 429150e8f8aSJiri Pirko BIT(DEVLINK_PARAM_CMODE_DRIVERINIT), 430150e8f8aSJiri Pirko NULL, NULL, NULL), 431150e8f8aSJiri Pirko }; 432150e8f8aSJiri Pirko 433150e8f8aSJiri Pirko static void nsim_devlink_set_params_init_values(struct nsim_dev *nsim_dev, 434150e8f8aSJiri Pirko struct devlink *devlink) 435150e8f8aSJiri Pirko { 436150e8f8aSJiri Pirko union devlink_param_value value; 437150e8f8aSJiri Pirko 438150e8f8aSJiri Pirko value.vu32 = nsim_dev->max_macs; 439150e8f8aSJiri Pirko devlink_param_driverinit_value_set(devlink, 440150e8f8aSJiri Pirko DEVLINK_PARAM_GENERIC_ID_MAX_MACS, 441150e8f8aSJiri Pirko value); 442150e8f8aSJiri Pirko value.vbool = nsim_dev->test1; 443150e8f8aSJiri Pirko devlink_param_driverinit_value_set(devlink, 444150e8f8aSJiri Pirko NSIM_DEVLINK_PARAM_ID_TEST1, 445150e8f8aSJiri Pirko value); 446150e8f8aSJiri Pirko } 447150e8f8aSJiri Pirko 448150e8f8aSJiri Pirko static void nsim_devlink_param_load_driverinit_values(struct devlink *devlink) 449150e8f8aSJiri Pirko { 450150e8f8aSJiri Pirko struct nsim_dev *nsim_dev = devlink_priv(devlink); 451150e8f8aSJiri Pirko union devlink_param_value saved_value; 452150e8f8aSJiri Pirko int err; 453150e8f8aSJiri Pirko 454150e8f8aSJiri Pirko err = devlink_param_driverinit_value_get(devlink, 455150e8f8aSJiri Pirko DEVLINK_PARAM_GENERIC_ID_MAX_MACS, 456150e8f8aSJiri Pirko &saved_value); 457150e8f8aSJiri Pirko if (!err) 458150e8f8aSJiri Pirko nsim_dev->max_macs = saved_value.vu32; 459150e8f8aSJiri Pirko err = devlink_param_driverinit_value_get(devlink, 460150e8f8aSJiri Pirko NSIM_DEVLINK_PARAM_ID_TEST1, 461150e8f8aSJiri Pirko &saved_value); 462150e8f8aSJiri Pirko if (!err) 463150e8f8aSJiri Pirko nsim_dev->test1 = saved_value.vbool; 464150e8f8aSJiri Pirko } 465150e8f8aSJiri Pirko 4664418f862SJiri Pirko #define NSIM_DEV_DUMMY_REGION_SNAPSHOT_MAX 16 4674418f862SJiri Pirko 468e8937681SJacob Keller static const struct devlink_region_ops dummy_region_ops = { 469e8937681SJacob Keller .name = "dummy", 470a0a09f6bSJacob Keller .destructor = &kfree, 4713fe0fd53SJacob Keller .snapshot = nsim_dev_take_snapshot, 472e8937681SJacob Keller }; 473e8937681SJacob Keller 4744418f862SJiri Pirko static int nsim_dev_dummy_region_init(struct nsim_dev *nsim_dev, 4754418f862SJiri Pirko struct devlink *devlink) 4764418f862SJiri Pirko { 4774418f862SJiri Pirko nsim_dev->dummy_region = 478e8937681SJacob Keller devlink_region_create(devlink, &dummy_region_ops, 4794418f862SJiri Pirko NSIM_DEV_DUMMY_REGION_SNAPSHOT_MAX, 4804418f862SJiri Pirko NSIM_DEV_DUMMY_REGION_SIZE); 4814418f862SJiri Pirko return PTR_ERR_OR_ZERO(nsim_dev->dummy_region); 4824418f862SJiri Pirko } 4834418f862SJiri Pirko 4844418f862SJiri Pirko static void nsim_dev_dummy_region_exit(struct nsim_dev *nsim_dev) 4854418f862SJiri Pirko { 4864418f862SJiri Pirko devlink_region_destroy(nsim_dev->dummy_region); 4874418f862SJiri Pirko } 4884418f862SJiri Pirko 489160dc373SDmytro Linkin static void __nsim_dev_port_del(struct nsim_dev_port *nsim_dev_port); 490160dc373SDmytro Linkin int nsim_esw_legacy_enable(struct nsim_dev *nsim_dev, struct netlink_ext_ack *extack) 491160dc373SDmytro Linkin { 492885226f5SDmytro Linkin struct devlink *devlink = priv_to_devlink(nsim_dev); 493160dc373SDmytro Linkin struct nsim_dev_port *nsim_dev_port, *tmp; 494160dc373SDmytro Linkin 495885226f5SDmytro Linkin devlink_rate_nodes_destroy(devlink); 496160dc373SDmytro Linkin mutex_lock(&nsim_dev->port_list_lock); 497160dc373SDmytro Linkin list_for_each_entry_safe(nsim_dev_port, tmp, &nsim_dev->port_list, list) 498160dc373SDmytro Linkin if (nsim_dev_port_is_vf(nsim_dev_port)) 499160dc373SDmytro Linkin __nsim_dev_port_del(nsim_dev_port); 500160dc373SDmytro Linkin mutex_unlock(&nsim_dev->port_list_lock); 501160dc373SDmytro Linkin nsim_dev->esw_mode = DEVLINK_ESWITCH_MODE_LEGACY; 502160dc373SDmytro Linkin return 0; 503160dc373SDmytro Linkin } 504160dc373SDmytro Linkin 505160dc373SDmytro Linkin int nsim_esw_switchdev_enable(struct nsim_dev *nsim_dev, struct netlink_ext_ack *extack) 506160dc373SDmytro Linkin { 507160dc373SDmytro Linkin struct nsim_bus_dev *nsim_bus_dev = nsim_dev->nsim_bus_dev; 508160dc373SDmytro Linkin int i, err; 509160dc373SDmytro Linkin 510160dc373SDmytro Linkin for (i = 0; i < nsim_bus_dev->num_vfs; i++) { 511160dc373SDmytro Linkin err = nsim_dev_port_add(nsim_bus_dev, NSIM_DEV_PORT_TYPE_VF, i); 512160dc373SDmytro Linkin if (err) { 513160dc373SDmytro Linkin NL_SET_ERR_MSG_MOD(extack, "Failed to initialize VFs' netdevsim ports"); 514160dc373SDmytro Linkin pr_err("Failed to initialize VF id=%d. %d.\n", i, err); 515160dc373SDmytro Linkin goto err_port_add_vfs; 516160dc373SDmytro Linkin } 517160dc373SDmytro Linkin } 518160dc373SDmytro Linkin nsim_dev->esw_mode = DEVLINK_ESWITCH_MODE_SWITCHDEV; 519160dc373SDmytro Linkin return 0; 520160dc373SDmytro Linkin 521160dc373SDmytro Linkin err_port_add_vfs: 522160dc373SDmytro Linkin for (i--; i >= 0; i--) 523160dc373SDmytro Linkin nsim_dev_port_del(nsim_bus_dev, NSIM_DEV_PORT_TYPE_VF, i); 524160dc373SDmytro Linkin return err; 525160dc373SDmytro Linkin } 526160dc373SDmytro Linkin 527160dc373SDmytro Linkin static int nsim_devlink_eswitch_mode_set(struct devlink *devlink, u16 mode, 528160dc373SDmytro Linkin struct netlink_ext_ack *extack) 529160dc373SDmytro Linkin { 530160dc373SDmytro Linkin struct nsim_dev *nsim_dev = devlink_priv(devlink); 531160dc373SDmytro Linkin int err = 0; 532160dc373SDmytro Linkin 533160dc373SDmytro Linkin mutex_lock(&nsim_dev->nsim_bus_dev->vfs_lock); 534160dc373SDmytro Linkin if (mode == nsim_dev->esw_mode) 535160dc373SDmytro Linkin goto unlock; 536160dc373SDmytro Linkin 537160dc373SDmytro Linkin if (mode == DEVLINK_ESWITCH_MODE_LEGACY) 538160dc373SDmytro Linkin err = nsim_esw_legacy_enable(nsim_dev, extack); 539160dc373SDmytro Linkin else if (mode == DEVLINK_ESWITCH_MODE_SWITCHDEV) 540160dc373SDmytro Linkin err = nsim_esw_switchdev_enable(nsim_dev, extack); 541160dc373SDmytro Linkin else 542160dc373SDmytro Linkin err = -EINVAL; 543160dc373SDmytro Linkin 544160dc373SDmytro Linkin unlock: 545160dc373SDmytro Linkin mutex_unlock(&nsim_dev->nsim_bus_dev->vfs_lock); 546160dc373SDmytro Linkin return err; 547160dc373SDmytro Linkin } 548160dc373SDmytro Linkin 549160dc373SDmytro Linkin static int nsim_devlink_eswitch_mode_get(struct devlink *devlink, u16 *mode) 550160dc373SDmytro Linkin { 551160dc373SDmytro Linkin struct nsim_dev *nsim_dev = devlink_priv(devlink); 552160dc373SDmytro Linkin 553160dc373SDmytro Linkin *mode = nsim_dev->esw_mode; 554160dc373SDmytro Linkin return 0; 555160dc373SDmytro Linkin } 556160dc373SDmytro Linkin 557da58f90fSIdo Schimmel struct nsim_trap_item { 558da58f90fSIdo Schimmel void *trap_ctx; 559da58f90fSIdo Schimmel enum devlink_trap_action action; 560da58f90fSIdo Schimmel }; 561da58f90fSIdo Schimmel 562da58f90fSIdo Schimmel struct nsim_trap_data { 563da58f90fSIdo Schimmel struct delayed_work trap_report_dw; 564da58f90fSIdo Schimmel struct nsim_trap_item *trap_items_arr; 565ad188458SIdo Schimmel u64 *trap_policers_cnt_arr; 566da58f90fSIdo Schimmel struct nsim_dev *nsim_dev; 567da58f90fSIdo Schimmel spinlock_t trap_lock; /* Protects trap_items_arr */ 568da58f90fSIdo Schimmel }; 569da58f90fSIdo Schimmel 5709e087457SIdo Schimmel /* All driver-specific traps must be documented in 57104e4272cSJacob Keller * Documentation/networking/devlink/netdevsim.rst 5729e087457SIdo Schimmel */ 573da58f90fSIdo Schimmel enum { 574da58f90fSIdo Schimmel NSIM_TRAP_ID_BASE = DEVLINK_TRAP_GENERIC_ID_MAX, 575da58f90fSIdo Schimmel NSIM_TRAP_ID_FID_MISS, 576da58f90fSIdo Schimmel }; 577da58f90fSIdo Schimmel 578da58f90fSIdo Schimmel #define NSIM_TRAP_NAME_FID_MISS "fid_miss" 579da58f90fSIdo Schimmel 580da58f90fSIdo Schimmel #define NSIM_TRAP_METADATA DEVLINK_TRAP_METADATA_TYPE_F_IN_PORT 581da58f90fSIdo Schimmel 582da58f90fSIdo Schimmel #define NSIM_TRAP_DROP(_id, _group_id) \ 583da58f90fSIdo Schimmel DEVLINK_TRAP_GENERIC(DROP, DROP, _id, \ 584107f1678SIdo Schimmel DEVLINK_TRAP_GROUP_GENERIC_ID_##_group_id, \ 585da58f90fSIdo Schimmel NSIM_TRAP_METADATA) 586d3cbb907SJiri Pirko #define NSIM_TRAP_DROP_EXT(_id, _group_id, _metadata) \ 587d3cbb907SJiri Pirko DEVLINK_TRAP_GENERIC(DROP, DROP, _id, \ 588107f1678SIdo Schimmel DEVLINK_TRAP_GROUP_GENERIC_ID_##_group_id, \ 589d3cbb907SJiri Pirko NSIM_TRAP_METADATA | (_metadata)) 590da58f90fSIdo Schimmel #define NSIM_TRAP_EXCEPTION(_id, _group_id) \ 591da58f90fSIdo Schimmel DEVLINK_TRAP_GENERIC(EXCEPTION, TRAP, _id, \ 592107f1678SIdo Schimmel DEVLINK_TRAP_GROUP_GENERIC_ID_##_group_id, \ 593da58f90fSIdo Schimmel NSIM_TRAP_METADATA) 59418979367SIdo Schimmel #define NSIM_TRAP_CONTROL(_id, _group_id, _action) \ 59518979367SIdo Schimmel DEVLINK_TRAP_GENERIC(CONTROL, _action, _id, \ 59618979367SIdo Schimmel DEVLINK_TRAP_GROUP_GENERIC_ID_##_group_id, \ 59718979367SIdo Schimmel NSIM_TRAP_METADATA) 598da58f90fSIdo Schimmel #define NSIM_TRAP_DRIVER_EXCEPTION(_id, _group_id) \ 599da58f90fSIdo Schimmel DEVLINK_TRAP_DRIVER(EXCEPTION, TRAP, NSIM_TRAP_ID_##_id, \ 600da58f90fSIdo Schimmel NSIM_TRAP_NAME_##_id, \ 601107f1678SIdo Schimmel DEVLINK_TRAP_GROUP_GENERIC_ID_##_group_id, \ 602da58f90fSIdo Schimmel NSIM_TRAP_METADATA) 603da58f90fSIdo Schimmel 604ad188458SIdo Schimmel #define NSIM_DEV_TRAP_POLICER_MIN_RATE 1 605ad188458SIdo Schimmel #define NSIM_DEV_TRAP_POLICER_MAX_RATE 8000 606ad188458SIdo Schimmel #define NSIM_DEV_TRAP_POLICER_MIN_BURST 8 607ad188458SIdo Schimmel #define NSIM_DEV_TRAP_POLICER_MAX_BURST 65536 608ad188458SIdo Schimmel 609ad188458SIdo Schimmel #define NSIM_TRAP_POLICER(_id, _rate, _burst) \ 610ad188458SIdo Schimmel DEVLINK_TRAP_POLICER(_id, _rate, _burst, \ 611ad188458SIdo Schimmel NSIM_DEV_TRAP_POLICER_MAX_RATE, \ 612ad188458SIdo Schimmel NSIM_DEV_TRAP_POLICER_MIN_RATE, \ 613ad188458SIdo Schimmel NSIM_DEV_TRAP_POLICER_MAX_BURST, \ 614ad188458SIdo Schimmel NSIM_DEV_TRAP_POLICER_MIN_BURST) 615ad188458SIdo Schimmel 616ad188458SIdo Schimmel static const struct devlink_trap_policer nsim_trap_policers_arr[] = { 617ad188458SIdo Schimmel NSIM_TRAP_POLICER(1, 1000, 128), 618ad188458SIdo Schimmel NSIM_TRAP_POLICER(2, 2000, 256), 619ad188458SIdo Schimmel NSIM_TRAP_POLICER(3, 3000, 512), 620ad188458SIdo Schimmel }; 621ad188458SIdo Schimmel 622b29545d8SIdo Schimmel static const struct devlink_trap_group nsim_trap_groups_arr[] = { 623f9f54392SIdo Schimmel DEVLINK_TRAP_GROUP_GENERIC(L2_DROPS, 0), 624f9f54392SIdo Schimmel DEVLINK_TRAP_GROUP_GENERIC(L3_DROPS, 1), 62585176f19SIdo Schimmel DEVLINK_TRAP_GROUP_GENERIC(L3_EXCEPTIONS, 1), 626f9f54392SIdo Schimmel DEVLINK_TRAP_GROUP_GENERIC(BUFFER_DROPS, 2), 627f9f54392SIdo Schimmel DEVLINK_TRAP_GROUP_GENERIC(ACL_DROPS, 3), 62818979367SIdo Schimmel DEVLINK_TRAP_GROUP_GENERIC(MC_SNOOPING, 3), 629b29545d8SIdo Schimmel }; 630b29545d8SIdo Schimmel 631da58f90fSIdo Schimmel static const struct devlink_trap nsim_traps_arr[] = { 632da58f90fSIdo Schimmel NSIM_TRAP_DROP(SMAC_MC, L2_DROPS), 633da58f90fSIdo Schimmel NSIM_TRAP_DROP(VLAN_TAG_MISMATCH, L2_DROPS), 634da58f90fSIdo Schimmel NSIM_TRAP_DROP(INGRESS_VLAN_FILTER, L2_DROPS), 635da58f90fSIdo Schimmel NSIM_TRAP_DROP(INGRESS_STP_FILTER, L2_DROPS), 636da58f90fSIdo Schimmel NSIM_TRAP_DROP(EMPTY_TX_LIST, L2_DROPS), 637da58f90fSIdo Schimmel NSIM_TRAP_DROP(PORT_LOOPBACK_FILTER, L2_DROPS), 638da58f90fSIdo Schimmel NSIM_TRAP_DRIVER_EXCEPTION(FID_MISS, L2_DROPS), 639da58f90fSIdo Schimmel NSIM_TRAP_DROP(BLACKHOLE_ROUTE, L3_DROPS), 64085176f19SIdo Schimmel NSIM_TRAP_EXCEPTION(TTL_ERROR, L3_EXCEPTIONS), 641da58f90fSIdo Schimmel NSIM_TRAP_DROP(TAIL_DROP, BUFFER_DROPS), 642d3cbb907SJiri Pirko NSIM_TRAP_DROP_EXT(INGRESS_FLOW_ACTION_DROP, ACL_DROPS, 643d3cbb907SJiri Pirko DEVLINK_TRAP_METADATA_TYPE_F_FA_COOKIE), 644d3cbb907SJiri Pirko NSIM_TRAP_DROP_EXT(EGRESS_FLOW_ACTION_DROP, ACL_DROPS, 645d3cbb907SJiri Pirko DEVLINK_TRAP_METADATA_TYPE_F_FA_COOKIE), 64618979367SIdo Schimmel NSIM_TRAP_CONTROL(IGMP_QUERY, MC_SNOOPING, MIRROR), 64718979367SIdo Schimmel NSIM_TRAP_CONTROL(IGMP_V1_REPORT, MC_SNOOPING, TRAP), 648da58f90fSIdo Schimmel }; 649da58f90fSIdo Schimmel 650da58f90fSIdo Schimmel #define NSIM_TRAP_L4_DATA_LEN 100 651da58f90fSIdo Schimmel 652da58f90fSIdo Schimmel static struct sk_buff *nsim_dev_trap_skb_build(void) 653da58f90fSIdo Schimmel { 654da58f90fSIdo Schimmel int tot_len, data_len = NSIM_TRAP_L4_DATA_LEN; 655da58f90fSIdo Schimmel struct sk_buff *skb; 656da58f90fSIdo Schimmel struct udphdr *udph; 657da58f90fSIdo Schimmel struct ethhdr *eth; 658da58f90fSIdo Schimmel struct iphdr *iph; 659da58f90fSIdo Schimmel 660da58f90fSIdo Schimmel skb = alloc_skb(NLMSG_GOODSIZE, GFP_ATOMIC); 661da58f90fSIdo Schimmel if (!skb) 662da58f90fSIdo Schimmel return NULL; 663da58f90fSIdo Schimmel tot_len = sizeof(struct iphdr) + sizeof(struct udphdr) + data_len; 664da58f90fSIdo Schimmel 66558a406deSIdo Schimmel skb_reset_mac_header(skb); 666da58f90fSIdo Schimmel eth = skb_put(skb, sizeof(struct ethhdr)); 667da58f90fSIdo Schimmel eth_random_addr(eth->h_dest); 668da58f90fSIdo Schimmel eth_random_addr(eth->h_source); 669da58f90fSIdo Schimmel eth->h_proto = htons(ETH_P_IP); 670da58f90fSIdo Schimmel skb->protocol = htons(ETH_P_IP); 671da58f90fSIdo Schimmel 67258a406deSIdo Schimmel skb_set_network_header(skb, skb->len); 673da58f90fSIdo Schimmel iph = skb_put(skb, sizeof(struct iphdr)); 674da58f90fSIdo Schimmel iph->protocol = IPPROTO_UDP; 675da58f90fSIdo Schimmel iph->saddr = in_aton("192.0.2.1"); 676da58f90fSIdo Schimmel iph->daddr = in_aton("198.51.100.1"); 677da58f90fSIdo Schimmel iph->version = 0x4; 678da58f90fSIdo Schimmel iph->frag_off = 0; 679da58f90fSIdo Schimmel iph->ihl = 0x5; 680da58f90fSIdo Schimmel iph->tot_len = htons(tot_len); 681da58f90fSIdo Schimmel iph->ttl = 100; 682d9bd6d27SYueHaibing iph->check = 0; 683d9bd6d27SYueHaibing iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl); 684da58f90fSIdo Schimmel 68558a406deSIdo Schimmel skb_set_transport_header(skb, skb->len); 686da58f90fSIdo Schimmel udph = skb_put_zero(skb, sizeof(struct udphdr) + data_len); 687da58f90fSIdo Schimmel get_random_bytes(&udph->source, sizeof(u16)); 688da58f90fSIdo Schimmel get_random_bytes(&udph->dest, sizeof(u16)); 689da58f90fSIdo Schimmel udph->len = htons(sizeof(struct udphdr) + data_len); 690da58f90fSIdo Schimmel 691da58f90fSIdo Schimmel return skb; 692da58f90fSIdo Schimmel } 693da58f90fSIdo Schimmel 694da58f90fSIdo Schimmel static void nsim_dev_trap_report(struct nsim_dev_port *nsim_dev_port) 695da58f90fSIdo Schimmel { 696da58f90fSIdo Schimmel struct nsim_dev *nsim_dev = nsim_dev_port->ns->nsim_dev; 697da58f90fSIdo Schimmel struct devlink *devlink = priv_to_devlink(nsim_dev); 698da58f90fSIdo Schimmel struct nsim_trap_data *nsim_trap_data; 699da58f90fSIdo Schimmel int i; 700da58f90fSIdo Schimmel 701da58f90fSIdo Schimmel nsim_trap_data = nsim_dev->trap_data; 702da58f90fSIdo Schimmel 703da58f90fSIdo Schimmel spin_lock(&nsim_trap_data->trap_lock); 704da58f90fSIdo Schimmel for (i = 0; i < ARRAY_SIZE(nsim_traps_arr); i++) { 705d3cbb907SJiri Pirko struct flow_action_cookie *fa_cookie = NULL; 706da58f90fSIdo Schimmel struct nsim_trap_item *nsim_trap_item; 707da58f90fSIdo Schimmel struct sk_buff *skb; 708d3cbb907SJiri Pirko bool has_fa_cookie; 709d3cbb907SJiri Pirko 710d3cbb907SJiri Pirko has_fa_cookie = nsim_traps_arr[i].metadata_cap & 711d3cbb907SJiri Pirko DEVLINK_TRAP_METADATA_TYPE_F_FA_COOKIE; 712da58f90fSIdo Schimmel 713da58f90fSIdo Schimmel nsim_trap_item = &nsim_trap_data->trap_items_arr[i]; 714da58f90fSIdo Schimmel if (nsim_trap_item->action == DEVLINK_TRAP_ACTION_DROP) 715da58f90fSIdo Schimmel continue; 716da58f90fSIdo Schimmel 717da58f90fSIdo Schimmel skb = nsim_dev_trap_skb_build(); 718da58f90fSIdo Schimmel if (!skb) 719da58f90fSIdo Schimmel continue; 720da58f90fSIdo Schimmel skb->dev = nsim_dev_port->ns->netdev; 721da58f90fSIdo Schimmel 722da58f90fSIdo Schimmel /* Trapped packets are usually passed to devlink in softIRQ, 723da58f90fSIdo Schimmel * but in this case they are generated in a workqueue. Disable 724da58f90fSIdo Schimmel * softIRQs to prevent lockdep from complaining about 725da58f90fSIdo Schimmel * "incosistent lock state". 726da58f90fSIdo Schimmel */ 727d3cbb907SJiri Pirko 728d3cbb907SJiri Pirko spin_lock_bh(&nsim_dev->fa_cookie_lock); 729d3cbb907SJiri Pirko fa_cookie = has_fa_cookie ? nsim_dev->fa_cookie : NULL; 730da58f90fSIdo Schimmel devlink_trap_report(devlink, skb, nsim_trap_item->trap_ctx, 731d3cbb907SJiri Pirko &nsim_dev_port->devlink_port, fa_cookie); 732d3cbb907SJiri Pirko spin_unlock_bh(&nsim_dev->fa_cookie_lock); 733da58f90fSIdo Schimmel consume_skb(skb); 734da58f90fSIdo Schimmel } 735da58f90fSIdo Schimmel spin_unlock(&nsim_trap_data->trap_lock); 736da58f90fSIdo Schimmel } 737da58f90fSIdo Schimmel 738da58f90fSIdo Schimmel #define NSIM_TRAP_REPORT_INTERVAL_MS 100 739da58f90fSIdo Schimmel 740da58f90fSIdo Schimmel static void nsim_dev_trap_report_work(struct work_struct *work) 741da58f90fSIdo Schimmel { 742da58f90fSIdo Schimmel struct nsim_trap_data *nsim_trap_data; 743da58f90fSIdo Schimmel struct nsim_dev_port *nsim_dev_port; 744da58f90fSIdo Schimmel struct nsim_dev *nsim_dev; 745da58f90fSIdo Schimmel 746da58f90fSIdo Schimmel nsim_trap_data = container_of(work, struct nsim_trap_data, 747da58f90fSIdo Schimmel trap_report_dw.work); 748da58f90fSIdo Schimmel nsim_dev = nsim_trap_data->nsim_dev; 749da58f90fSIdo Schimmel 750da58f90fSIdo Schimmel /* For each running port and enabled packet trap, generate a UDP 751da58f90fSIdo Schimmel * packet with a random 5-tuple and report it. 752da58f90fSIdo Schimmel */ 753da58f90fSIdo Schimmel mutex_lock(&nsim_dev->port_list_lock); 754da58f90fSIdo Schimmel list_for_each_entry(nsim_dev_port, &nsim_dev->port_list, list) { 755da58f90fSIdo Schimmel if (!netif_running(nsim_dev_port->ns->netdev)) 756da58f90fSIdo Schimmel continue; 757da58f90fSIdo Schimmel 758da58f90fSIdo Schimmel nsim_dev_trap_report(nsim_dev_port); 759da58f90fSIdo Schimmel } 760da58f90fSIdo Schimmel mutex_unlock(&nsim_dev->port_list_lock); 761da58f90fSIdo Schimmel 762da58f90fSIdo Schimmel schedule_delayed_work(&nsim_dev->trap_data->trap_report_dw, 763da58f90fSIdo Schimmel msecs_to_jiffies(NSIM_TRAP_REPORT_INTERVAL_MS)); 764da58f90fSIdo Schimmel } 765da58f90fSIdo Schimmel 766da58f90fSIdo Schimmel static int nsim_dev_traps_init(struct devlink *devlink) 767da58f90fSIdo Schimmel { 768ad188458SIdo Schimmel size_t policers_count = ARRAY_SIZE(nsim_trap_policers_arr); 769da58f90fSIdo Schimmel struct nsim_dev *nsim_dev = devlink_priv(devlink); 770da58f90fSIdo Schimmel struct nsim_trap_data *nsim_trap_data; 771da58f90fSIdo Schimmel int err; 772da58f90fSIdo Schimmel 773da58f90fSIdo Schimmel nsim_trap_data = kzalloc(sizeof(*nsim_trap_data), GFP_KERNEL); 774da58f90fSIdo Schimmel if (!nsim_trap_data) 775da58f90fSIdo Schimmel return -ENOMEM; 776da58f90fSIdo Schimmel 777da58f90fSIdo Schimmel nsim_trap_data->trap_items_arr = kcalloc(ARRAY_SIZE(nsim_traps_arr), 778da58f90fSIdo Schimmel sizeof(struct nsim_trap_item), 779da58f90fSIdo Schimmel GFP_KERNEL); 780da58f90fSIdo Schimmel if (!nsim_trap_data->trap_items_arr) { 781da58f90fSIdo Schimmel err = -ENOMEM; 782da58f90fSIdo Schimmel goto err_trap_data_free; 783da58f90fSIdo Schimmel } 784da58f90fSIdo Schimmel 785ad188458SIdo Schimmel nsim_trap_data->trap_policers_cnt_arr = kcalloc(policers_count, 786ad188458SIdo Schimmel sizeof(u64), 787ad188458SIdo Schimmel GFP_KERNEL); 788ad188458SIdo Schimmel if (!nsim_trap_data->trap_policers_cnt_arr) { 789ad188458SIdo Schimmel err = -ENOMEM; 790ad188458SIdo Schimmel goto err_trap_items_free; 791ad188458SIdo Schimmel } 792ad188458SIdo Schimmel 793da58f90fSIdo Schimmel /* The lock is used to protect the action state of the registered 794da58f90fSIdo Schimmel * traps. The value is written by user and read in delayed work when 795da58f90fSIdo Schimmel * iterating over all the traps. 796da58f90fSIdo Schimmel */ 797da58f90fSIdo Schimmel spin_lock_init(&nsim_trap_data->trap_lock); 798da58f90fSIdo Schimmel nsim_trap_data->nsim_dev = nsim_dev; 799da58f90fSIdo Schimmel nsim_dev->trap_data = nsim_trap_data; 800da58f90fSIdo Schimmel 801ad188458SIdo Schimmel err = devlink_trap_policers_register(devlink, nsim_trap_policers_arr, 802ad188458SIdo Schimmel policers_count); 803ad188458SIdo Schimmel if (err) 804ad188458SIdo Schimmel goto err_trap_policers_cnt_free; 805ad188458SIdo Schimmel 806b29545d8SIdo Schimmel err = devlink_trap_groups_register(devlink, nsim_trap_groups_arr, 807b29545d8SIdo Schimmel ARRAY_SIZE(nsim_trap_groups_arr)); 808b29545d8SIdo Schimmel if (err) 809ad188458SIdo Schimmel goto err_trap_policers_unregister; 810b29545d8SIdo Schimmel 811da58f90fSIdo Schimmel err = devlink_traps_register(devlink, nsim_traps_arr, 812da58f90fSIdo Schimmel ARRAY_SIZE(nsim_traps_arr), NULL); 813da58f90fSIdo Schimmel if (err) 814b29545d8SIdo Schimmel goto err_trap_groups_unregister; 815da58f90fSIdo Schimmel 816da58f90fSIdo Schimmel INIT_DELAYED_WORK(&nsim_dev->trap_data->trap_report_dw, 817da58f90fSIdo Schimmel nsim_dev_trap_report_work); 818da58f90fSIdo Schimmel schedule_delayed_work(&nsim_dev->trap_data->trap_report_dw, 819da58f90fSIdo Schimmel msecs_to_jiffies(NSIM_TRAP_REPORT_INTERVAL_MS)); 820da58f90fSIdo Schimmel 821da58f90fSIdo Schimmel return 0; 822da58f90fSIdo Schimmel 823b29545d8SIdo Schimmel err_trap_groups_unregister: 824b29545d8SIdo Schimmel devlink_trap_groups_unregister(devlink, nsim_trap_groups_arr, 825b29545d8SIdo Schimmel ARRAY_SIZE(nsim_trap_groups_arr)); 826ad188458SIdo Schimmel err_trap_policers_unregister: 827ad188458SIdo Schimmel devlink_trap_policers_unregister(devlink, nsim_trap_policers_arr, 828ad188458SIdo Schimmel ARRAY_SIZE(nsim_trap_policers_arr)); 829ad188458SIdo Schimmel err_trap_policers_cnt_free: 830ad188458SIdo Schimmel kfree(nsim_trap_data->trap_policers_cnt_arr); 831da58f90fSIdo Schimmel err_trap_items_free: 832da58f90fSIdo Schimmel kfree(nsim_trap_data->trap_items_arr); 833da58f90fSIdo Schimmel err_trap_data_free: 834da58f90fSIdo Schimmel kfree(nsim_trap_data); 835da58f90fSIdo Schimmel return err; 836da58f90fSIdo Schimmel } 837da58f90fSIdo Schimmel 838da58f90fSIdo Schimmel static void nsim_dev_traps_exit(struct devlink *devlink) 839da58f90fSIdo Schimmel { 840da58f90fSIdo Schimmel struct nsim_dev *nsim_dev = devlink_priv(devlink); 841da58f90fSIdo Schimmel 842da58f90fSIdo Schimmel cancel_delayed_work_sync(&nsim_dev->trap_data->trap_report_dw); 843da58f90fSIdo Schimmel devlink_traps_unregister(devlink, nsim_traps_arr, 844da58f90fSIdo Schimmel ARRAY_SIZE(nsim_traps_arr)); 845b29545d8SIdo Schimmel devlink_trap_groups_unregister(devlink, nsim_trap_groups_arr, 846b29545d8SIdo Schimmel ARRAY_SIZE(nsim_trap_groups_arr)); 847ad188458SIdo Schimmel devlink_trap_policers_unregister(devlink, nsim_trap_policers_arr, 848ad188458SIdo Schimmel ARRAY_SIZE(nsim_trap_policers_arr)); 849ad188458SIdo Schimmel kfree(nsim_dev->trap_data->trap_policers_cnt_arr); 850da58f90fSIdo Schimmel kfree(nsim_dev->trap_data->trap_items_arr); 851da58f90fSIdo Schimmel kfree(nsim_dev->trap_data); 852da58f90fSIdo Schimmel } 853da58f90fSIdo Schimmel 85475ba029fSJiri Pirko static int nsim_dev_reload_create(struct nsim_dev *nsim_dev, 85575ba029fSJiri Pirko struct netlink_ext_ack *extack); 85675ba029fSJiri Pirko static void nsim_dev_reload_destroy(struct nsim_dev *nsim_dev); 85775ba029fSJiri Pirko 858070c63f2SJiri Pirko static int nsim_dev_reload_down(struct devlink *devlink, bool netns_change, 859dc64cc7cSMoshe Shemesh enum devlink_reload_action action, enum devlink_reload_limit limit, 860dc64cc7cSMoshe Shemesh struct netlink_ext_ack *extack) 86197691069SJiri Pirko { 86275ba029fSJiri Pirko struct nsim_dev *nsim_dev = devlink_priv(devlink); 86375ba029fSJiri Pirko 864155ddfc5SJiri Pirko if (nsim_dev->dont_allow_reload) { 865155ddfc5SJiri Pirko /* For testing purposes, user set debugfs dont_allow_reload 866155ddfc5SJiri Pirko * value to true. So forbid it. 867155ddfc5SJiri Pirko */ 868f9867b51SColin Ian King NL_SET_ERR_MSG_MOD(extack, "User forbid the reload for testing purposes"); 869155ddfc5SJiri Pirko return -EOPNOTSUPP; 870155ddfc5SJiri Pirko } 871155ddfc5SJiri Pirko 87275ba029fSJiri Pirko nsim_dev_reload_destroy(nsim_dev); 87397691069SJiri Pirko return 0; 87497691069SJiri Pirko } 87597691069SJiri Pirko 876ccdf0721SMoshe Shemesh static int nsim_dev_reload_up(struct devlink *devlink, enum devlink_reload_action action, 877dc64cc7cSMoshe Shemesh enum devlink_reload_limit limit, u32 *actions_performed, 878dc64cc7cSMoshe Shemesh struct netlink_ext_ack *extack) 8798fb4bc6fSJiri Pirko { 880a5facc4cSJiri Pirko struct nsim_dev *nsim_dev = devlink_priv(devlink); 8818fb4bc6fSJiri Pirko 882155ddfc5SJiri Pirko if (nsim_dev->fail_reload) { 883155ddfc5SJiri Pirko /* For testing purposes, user set debugfs fail_reload 884155ddfc5SJiri Pirko * value to true. Fail right away. 885155ddfc5SJiri Pirko */ 886155ddfc5SJiri Pirko NL_SET_ERR_MSG_MOD(extack, "User setup the reload to fail for testing purposes"); 887155ddfc5SJiri Pirko return -EINVAL; 888155ddfc5SJiri Pirko } 889155ddfc5SJiri Pirko 890ccdf0721SMoshe Shemesh *actions_performed = BIT(DEVLINK_RELOAD_ACTION_DRIVER_REINIT); 89175ba029fSJiri Pirko return nsim_dev_reload_create(nsim_dev, extack); 8928fb4bc6fSJiri Pirko } 8938fb4bc6fSJiri Pirko 8948e23cc03SJiri Pirko static int nsim_dev_info_get(struct devlink *devlink, 8958e23cc03SJiri Pirko struct devlink_info_req *req, 8968e23cc03SJiri Pirko struct netlink_ext_ack *extack) 8978e23cc03SJiri Pirko { 8988e23cc03SJiri Pirko return devlink_info_driver_name_put(req, DRV_NAME); 8998e23cc03SJiri Pirko } 9008e23cc03SJiri Pirko 901fa4dfc4aSJiri Pirko #define NSIM_DEV_FLASH_SIZE 500000 902fa4dfc4aSJiri Pirko #define NSIM_DEV_FLASH_CHUNK_SIZE 1000 903fa4dfc4aSJiri Pirko #define NSIM_DEV_FLASH_CHUNK_TIME_MS 10 904fa4dfc4aSJiri Pirko 905bc75c054SJacob Keller static int nsim_dev_flash_update(struct devlink *devlink, 906bc75c054SJacob Keller struct devlink_flash_update_params *params, 907fa4dfc4aSJiri Pirko struct netlink_ext_ack *extack) 908fa4dfc4aSJiri Pirko { 909fa4dfc4aSJiri Pirko struct nsim_dev *nsim_dev = devlink_priv(devlink); 910fa4dfc4aSJiri Pirko int i; 911fa4dfc4aSJiri Pirko 912cbb58368SJacob Keller if ((params->overwrite_mask & ~nsim_dev->fw_update_overwrite_mask) != 0) 913cbb58368SJacob Keller return -EOPNOTSUPP; 914cbb58368SJacob Keller 915fa4dfc4aSJiri Pirko if (nsim_dev->fw_update_status) { 916fa4dfc4aSJiri Pirko devlink_flash_update_status_notify(devlink, 917fa4dfc4aSJiri Pirko "Preparing to flash", 918bc75c054SJacob Keller params->component, 0, 0); 919fa4dfc4aSJiri Pirko } 920fa4dfc4aSJiri Pirko 921fa4dfc4aSJiri Pirko for (i = 0; i < NSIM_DEV_FLASH_SIZE / NSIM_DEV_FLASH_CHUNK_SIZE; i++) { 922fa4dfc4aSJiri Pirko if (nsim_dev->fw_update_status) 923fa4dfc4aSJiri Pirko devlink_flash_update_status_notify(devlink, "Flashing", 924bc75c054SJacob Keller params->component, 925fa4dfc4aSJiri Pirko i * NSIM_DEV_FLASH_CHUNK_SIZE, 926fa4dfc4aSJiri Pirko NSIM_DEV_FLASH_SIZE); 927fa4dfc4aSJiri Pirko msleep(NSIM_DEV_FLASH_CHUNK_TIME_MS); 928fa4dfc4aSJiri Pirko } 929fa4dfc4aSJiri Pirko 930fa4dfc4aSJiri Pirko if (nsim_dev->fw_update_status) { 931fa4dfc4aSJiri Pirko devlink_flash_update_status_notify(devlink, "Flashing", 932bc75c054SJacob Keller params->component, 933fa4dfc4aSJiri Pirko NSIM_DEV_FLASH_SIZE, 934fa4dfc4aSJiri Pirko NSIM_DEV_FLASH_SIZE); 935b311b001SShannon Nelson devlink_flash_update_timeout_notify(devlink, "Flash select", 936bc75c054SJacob Keller params->component, 81); 937fa4dfc4aSJiri Pirko devlink_flash_update_status_notify(devlink, "Flashing done", 938bc75c054SJacob Keller params->component, 0, 0); 939fa4dfc4aSJiri Pirko } 940fa4dfc4aSJiri Pirko 941fa4dfc4aSJiri Pirko return 0; 942fa4dfc4aSJiri Pirko } 943fa4dfc4aSJiri Pirko 944da58f90fSIdo Schimmel static struct nsim_trap_item * 945da58f90fSIdo Schimmel nsim_dev_trap_item_lookup(struct nsim_dev *nsim_dev, u16 trap_id) 946da58f90fSIdo Schimmel { 947da58f90fSIdo Schimmel struct nsim_trap_data *nsim_trap_data = nsim_dev->trap_data; 948da58f90fSIdo Schimmel int i; 949da58f90fSIdo Schimmel 950da58f90fSIdo Schimmel for (i = 0; i < ARRAY_SIZE(nsim_traps_arr); i++) { 951da58f90fSIdo Schimmel if (nsim_traps_arr[i].id == trap_id) 952da58f90fSIdo Schimmel return &nsim_trap_data->trap_items_arr[i]; 953da58f90fSIdo Schimmel } 954da58f90fSIdo Schimmel 955da58f90fSIdo Schimmel return NULL; 956da58f90fSIdo Schimmel } 957da58f90fSIdo Schimmel 958da58f90fSIdo Schimmel static int nsim_dev_devlink_trap_init(struct devlink *devlink, 959da58f90fSIdo Schimmel const struct devlink_trap *trap, 960da58f90fSIdo Schimmel void *trap_ctx) 961da58f90fSIdo Schimmel { 962da58f90fSIdo Schimmel struct nsim_dev *nsim_dev = devlink_priv(devlink); 963da58f90fSIdo Schimmel struct nsim_trap_item *nsim_trap_item; 964da58f90fSIdo Schimmel 965da58f90fSIdo Schimmel nsim_trap_item = nsim_dev_trap_item_lookup(nsim_dev, trap->id); 966da58f90fSIdo Schimmel if (WARN_ON(!nsim_trap_item)) 967da58f90fSIdo Schimmel return -ENOENT; 968da58f90fSIdo Schimmel 969da58f90fSIdo Schimmel nsim_trap_item->trap_ctx = trap_ctx; 970da58f90fSIdo Schimmel nsim_trap_item->action = trap->init_action; 971da58f90fSIdo Schimmel 972da58f90fSIdo Schimmel return 0; 973da58f90fSIdo Schimmel } 974da58f90fSIdo Schimmel 975da58f90fSIdo Schimmel static int 976da58f90fSIdo Schimmel nsim_dev_devlink_trap_action_set(struct devlink *devlink, 977da58f90fSIdo Schimmel const struct devlink_trap *trap, 978c88e11e0SIdo Schimmel enum devlink_trap_action action, 979c88e11e0SIdo Schimmel struct netlink_ext_ack *extack) 980da58f90fSIdo Schimmel { 981da58f90fSIdo Schimmel struct nsim_dev *nsim_dev = devlink_priv(devlink); 982da58f90fSIdo Schimmel struct nsim_trap_item *nsim_trap_item; 983da58f90fSIdo Schimmel 984da58f90fSIdo Schimmel nsim_trap_item = nsim_dev_trap_item_lookup(nsim_dev, trap->id); 985da58f90fSIdo Schimmel if (WARN_ON(!nsim_trap_item)) 986da58f90fSIdo Schimmel return -ENOENT; 987da58f90fSIdo Schimmel 988da58f90fSIdo Schimmel spin_lock(&nsim_dev->trap_data->trap_lock); 989da58f90fSIdo Schimmel nsim_trap_item->action = action; 990da58f90fSIdo Schimmel spin_unlock(&nsim_dev->trap_data->trap_lock); 991da58f90fSIdo Schimmel 992da58f90fSIdo Schimmel return 0; 993da58f90fSIdo Schimmel } 994da58f90fSIdo Schimmel 995ad188458SIdo Schimmel static int 9960dc8249aSIdo Schimmel nsim_dev_devlink_trap_group_set(struct devlink *devlink, 9970dc8249aSIdo Schimmel const struct devlink_trap_group *group, 998c88e11e0SIdo Schimmel const struct devlink_trap_policer *policer, 999c88e11e0SIdo Schimmel struct netlink_ext_ack *extack) 10000dc8249aSIdo Schimmel { 10010dc8249aSIdo Schimmel struct nsim_dev *nsim_dev = devlink_priv(devlink); 10020dc8249aSIdo Schimmel 10030dc8249aSIdo Schimmel if (nsim_dev->fail_trap_group_set) 10040dc8249aSIdo Schimmel return -EINVAL; 10050dc8249aSIdo Schimmel 10060dc8249aSIdo Schimmel return 0; 10070dc8249aSIdo Schimmel } 10080dc8249aSIdo Schimmel 10090dc8249aSIdo Schimmel static int 1010ad188458SIdo Schimmel nsim_dev_devlink_trap_policer_set(struct devlink *devlink, 1011ad188458SIdo Schimmel const struct devlink_trap_policer *policer, 1012ad188458SIdo Schimmel u64 rate, u64 burst, 1013ad188458SIdo Schimmel struct netlink_ext_ack *extack) 1014ad188458SIdo Schimmel { 1015ad188458SIdo Schimmel struct nsim_dev *nsim_dev = devlink_priv(devlink); 1016ad188458SIdo Schimmel 1017ad188458SIdo Schimmel if (nsim_dev->fail_trap_policer_set) { 1018ad188458SIdo Schimmel NL_SET_ERR_MSG_MOD(extack, "User setup the operation to fail for testing purposes"); 1019ad188458SIdo Schimmel return -EINVAL; 1020ad188458SIdo Schimmel } 1021ad188458SIdo Schimmel 1022ad188458SIdo Schimmel return 0; 1023ad188458SIdo Schimmel } 1024ad188458SIdo Schimmel 1025ad188458SIdo Schimmel static int 1026ad188458SIdo Schimmel nsim_dev_devlink_trap_policer_counter_get(struct devlink *devlink, 1027ad188458SIdo Schimmel const struct devlink_trap_policer *policer, 1028ad188458SIdo Schimmel u64 *p_drops) 1029ad188458SIdo Schimmel { 1030ad188458SIdo Schimmel struct nsim_dev *nsim_dev = devlink_priv(devlink); 1031ad188458SIdo Schimmel u64 *cnt; 1032ad188458SIdo Schimmel 1033ad188458SIdo Schimmel if (nsim_dev->fail_trap_policer_counter_get) 1034ad188458SIdo Schimmel return -EINVAL; 1035ad188458SIdo Schimmel 1036ad188458SIdo Schimmel cnt = &nsim_dev->trap_data->trap_policers_cnt_arr[policer->id - 1]; 1037be43224fSIdo Schimmel *p_drops = (*cnt)++; 1038ad188458SIdo Schimmel 1039ad188458SIdo Schimmel return 0; 1040ad188458SIdo Schimmel } 1041ad188458SIdo Schimmel 1042605c4f8fSDmytro Linkin #define NSIM_LINK_SPEED_MAX 5000 /* Mbps */ 1043605c4f8fSDmytro Linkin #define NSIM_LINK_SPEED_UNIT 125000 /* 1 Mbps given in bytes/sec to avoid 1044605c4f8fSDmytro Linkin * u64 overflow during conversion from 1045605c4f8fSDmytro Linkin * bytes to bits. 1046605c4f8fSDmytro Linkin */ 1047605c4f8fSDmytro Linkin 1048605c4f8fSDmytro Linkin static int nsim_rate_bytes_to_units(char *name, u64 *rate, struct netlink_ext_ack *extack) 1049605c4f8fSDmytro Linkin { 1050605c4f8fSDmytro Linkin u64 val; 1051605c4f8fSDmytro Linkin u32 rem; 1052605c4f8fSDmytro Linkin 1053605c4f8fSDmytro Linkin val = div_u64_rem(*rate, NSIM_LINK_SPEED_UNIT, &rem); 1054605c4f8fSDmytro Linkin if (rem) { 1055605c4f8fSDmytro Linkin pr_err("%s rate value %lluBps not in link speed units of 1Mbps.\n", 1056605c4f8fSDmytro Linkin name, *rate); 1057605c4f8fSDmytro Linkin NL_SET_ERR_MSG_MOD(extack, "TX rate value not in link speed units of 1Mbps."); 1058605c4f8fSDmytro Linkin return -EINVAL; 1059605c4f8fSDmytro Linkin } 1060605c4f8fSDmytro Linkin 1061605c4f8fSDmytro Linkin if (val > NSIM_LINK_SPEED_MAX) { 1062605c4f8fSDmytro Linkin pr_err("%s rate value %lluMbps exceed link maximum speed 5000Mbps.\n", 1063605c4f8fSDmytro Linkin name, val); 1064605c4f8fSDmytro Linkin NL_SET_ERR_MSG_MOD(extack, "TX rate value exceed link maximum speed 5000Mbps."); 1065605c4f8fSDmytro Linkin return -EINVAL; 1066605c4f8fSDmytro Linkin } 1067605c4f8fSDmytro Linkin *rate = val; 1068605c4f8fSDmytro Linkin return 0; 1069605c4f8fSDmytro Linkin } 1070605c4f8fSDmytro Linkin 1071605c4f8fSDmytro Linkin static int nsim_leaf_tx_share_set(struct devlink_rate *devlink_rate, void *priv, 1072605c4f8fSDmytro Linkin u64 tx_share, struct netlink_ext_ack *extack) 1073605c4f8fSDmytro Linkin { 1074605c4f8fSDmytro Linkin struct nsim_dev_port *nsim_dev_port = priv; 1075605c4f8fSDmytro Linkin struct nsim_bus_dev *nsim_bus_dev = nsim_dev_port->ns->nsim_bus_dev; 1076605c4f8fSDmytro Linkin int vf_id = nsim_dev_port_index_to_vf_index(nsim_dev_port->port_index); 1077605c4f8fSDmytro Linkin int err; 1078605c4f8fSDmytro Linkin 1079605c4f8fSDmytro Linkin err = nsim_rate_bytes_to_units("tx_share", &tx_share, extack); 1080605c4f8fSDmytro Linkin if (err) 1081605c4f8fSDmytro Linkin return err; 1082605c4f8fSDmytro Linkin 1083605c4f8fSDmytro Linkin nsim_bus_dev->vfconfigs[vf_id].min_tx_rate = tx_share; 1084605c4f8fSDmytro Linkin return 0; 1085605c4f8fSDmytro Linkin } 1086605c4f8fSDmytro Linkin 1087605c4f8fSDmytro Linkin static int nsim_leaf_tx_max_set(struct devlink_rate *devlink_rate, void *priv, 1088605c4f8fSDmytro Linkin u64 tx_max, struct netlink_ext_ack *extack) 1089605c4f8fSDmytro Linkin { 1090605c4f8fSDmytro Linkin struct nsim_dev_port *nsim_dev_port = priv; 1091605c4f8fSDmytro Linkin struct nsim_bus_dev *nsim_bus_dev = nsim_dev_port->ns->nsim_bus_dev; 1092605c4f8fSDmytro Linkin int vf_id = nsim_dev_port_index_to_vf_index(nsim_dev_port->port_index); 1093605c4f8fSDmytro Linkin int err; 1094605c4f8fSDmytro Linkin 1095605c4f8fSDmytro Linkin err = nsim_rate_bytes_to_units("tx_max", &tx_max, extack); 1096605c4f8fSDmytro Linkin if (err) 1097605c4f8fSDmytro Linkin return err; 1098605c4f8fSDmytro Linkin 1099605c4f8fSDmytro Linkin nsim_bus_dev->vfconfigs[vf_id].max_tx_rate = tx_max; 1100605c4f8fSDmytro Linkin return 0; 1101605c4f8fSDmytro Linkin } 1102605c4f8fSDmytro Linkin 1103885226f5SDmytro Linkin struct nsim_rate_node { 1104885226f5SDmytro Linkin struct dentry *ddir; 1105f3d101b4SDmytro Linkin struct dentry *rate_parent; 1106f3d101b4SDmytro Linkin char *parent_name; 1107885226f5SDmytro Linkin u16 tx_share; 1108885226f5SDmytro Linkin u16 tx_max; 1109885226f5SDmytro Linkin }; 1110885226f5SDmytro Linkin 1111885226f5SDmytro Linkin static int nsim_node_tx_share_set(struct devlink_rate *devlink_rate, void *priv, 1112885226f5SDmytro Linkin u64 tx_share, struct netlink_ext_ack *extack) 1113885226f5SDmytro Linkin { 1114885226f5SDmytro Linkin struct nsim_rate_node *nsim_node = priv; 1115885226f5SDmytro Linkin int err; 1116885226f5SDmytro Linkin 1117885226f5SDmytro Linkin err = nsim_rate_bytes_to_units("tx_share", &tx_share, extack); 1118885226f5SDmytro Linkin if (err) 1119885226f5SDmytro Linkin return err; 1120885226f5SDmytro Linkin 1121885226f5SDmytro Linkin nsim_node->tx_share = tx_share; 1122885226f5SDmytro Linkin return 0; 1123885226f5SDmytro Linkin } 1124885226f5SDmytro Linkin 1125885226f5SDmytro Linkin static int nsim_node_tx_max_set(struct devlink_rate *devlink_rate, void *priv, 1126885226f5SDmytro Linkin u64 tx_max, struct netlink_ext_ack *extack) 1127885226f5SDmytro Linkin { 1128885226f5SDmytro Linkin struct nsim_rate_node *nsim_node = priv; 1129885226f5SDmytro Linkin int err; 1130885226f5SDmytro Linkin 1131885226f5SDmytro Linkin err = nsim_rate_bytes_to_units("tx_max", &tx_max, extack); 1132885226f5SDmytro Linkin if (err) 1133885226f5SDmytro Linkin return err; 1134885226f5SDmytro Linkin 1135885226f5SDmytro Linkin nsim_node->tx_max = tx_max; 1136885226f5SDmytro Linkin return 0; 1137885226f5SDmytro Linkin } 1138885226f5SDmytro Linkin 1139885226f5SDmytro Linkin static int nsim_rate_node_new(struct devlink_rate *node, void **priv, 1140885226f5SDmytro Linkin struct netlink_ext_ack *extack) 1141885226f5SDmytro Linkin { 1142885226f5SDmytro Linkin struct nsim_dev *nsim_dev = devlink_priv(node->devlink); 1143885226f5SDmytro Linkin struct nsim_rate_node *nsim_node; 1144885226f5SDmytro Linkin 1145885226f5SDmytro Linkin if (!nsim_esw_mode_is_switchdev(nsim_dev)) { 1146885226f5SDmytro Linkin NL_SET_ERR_MSG_MOD(extack, "Node creation allowed only in switchdev mode."); 1147885226f5SDmytro Linkin return -EOPNOTSUPP; 1148885226f5SDmytro Linkin } 1149885226f5SDmytro Linkin 1150885226f5SDmytro Linkin nsim_node = kzalloc(sizeof(*nsim_node), GFP_KERNEL); 1151885226f5SDmytro Linkin if (!nsim_node) 1152885226f5SDmytro Linkin return -ENOMEM; 1153885226f5SDmytro Linkin 1154885226f5SDmytro Linkin nsim_node->ddir = debugfs_create_dir(node->name, nsim_dev->nodes_ddir); 1155*4e744cb8SDan Carpenter 1156885226f5SDmytro Linkin debugfs_create_u16("tx_share", 0400, nsim_node->ddir, &nsim_node->tx_share); 1157885226f5SDmytro Linkin debugfs_create_u16("tx_max", 0400, nsim_node->ddir, &nsim_node->tx_max); 1158f3d101b4SDmytro Linkin nsim_node->rate_parent = debugfs_create_file("rate_parent", 0400, 1159f3d101b4SDmytro Linkin nsim_node->ddir, 1160f3d101b4SDmytro Linkin &nsim_node->parent_name, 1161f3d101b4SDmytro Linkin &nsim_dev_rate_parent_fops); 1162f3d101b4SDmytro Linkin 1163885226f5SDmytro Linkin *priv = nsim_node; 1164885226f5SDmytro Linkin return 0; 1165885226f5SDmytro Linkin } 1166885226f5SDmytro Linkin 1167885226f5SDmytro Linkin static int nsim_rate_node_del(struct devlink_rate *node, void *priv, 1168885226f5SDmytro Linkin struct netlink_ext_ack *extack) 1169885226f5SDmytro Linkin { 1170885226f5SDmytro Linkin struct nsim_rate_node *nsim_node = priv; 1171885226f5SDmytro Linkin 1172f3d101b4SDmytro Linkin debugfs_remove(nsim_node->rate_parent); 1173885226f5SDmytro Linkin debugfs_remove_recursive(nsim_node->ddir); 1174885226f5SDmytro Linkin kfree(nsim_node); 1175885226f5SDmytro Linkin return 0; 1176885226f5SDmytro Linkin } 1177885226f5SDmytro Linkin 1178f3d101b4SDmytro Linkin static int nsim_rate_leaf_parent_set(struct devlink_rate *child, 1179f3d101b4SDmytro Linkin struct devlink_rate *parent, 1180f3d101b4SDmytro Linkin void *priv_child, void *priv_parent, 1181f3d101b4SDmytro Linkin struct netlink_ext_ack *extack) 1182f3d101b4SDmytro Linkin { 1183f3d101b4SDmytro Linkin struct nsim_dev_port *nsim_dev_port = priv_child; 1184f3d101b4SDmytro Linkin 1185f3d101b4SDmytro Linkin if (parent) 1186f3d101b4SDmytro Linkin nsim_dev_port->parent_name = parent->name; 1187f3d101b4SDmytro Linkin else 1188f3d101b4SDmytro Linkin nsim_dev_port->parent_name = NULL; 1189f3d101b4SDmytro Linkin return 0; 1190f3d101b4SDmytro Linkin } 1191f3d101b4SDmytro Linkin 1192f3d101b4SDmytro Linkin static int nsim_rate_node_parent_set(struct devlink_rate *child, 1193f3d101b4SDmytro Linkin struct devlink_rate *parent, 1194f3d101b4SDmytro Linkin void *priv_child, void *priv_parent, 1195f3d101b4SDmytro Linkin struct netlink_ext_ack *extack) 1196f3d101b4SDmytro Linkin { 1197f3d101b4SDmytro Linkin struct nsim_rate_node *nsim_node = priv_child; 1198f3d101b4SDmytro Linkin 1199f3d101b4SDmytro Linkin if (parent) 1200f3d101b4SDmytro Linkin nsim_node->parent_name = parent->name; 1201f3d101b4SDmytro Linkin else 1202f3d101b4SDmytro Linkin nsim_node->parent_name = NULL; 1203f3d101b4SDmytro Linkin return 0; 1204f3d101b4SDmytro Linkin } 1205f3d101b4SDmytro Linkin 12068fb4bc6fSJiri Pirko static const struct devlink_ops nsim_dev_devlink_ops = { 1207160dc373SDmytro Linkin .eswitch_mode_set = nsim_devlink_eswitch_mode_set, 1208160dc373SDmytro Linkin .eswitch_mode_get = nsim_devlink_eswitch_mode_get, 1209cbb58368SJacob Keller .supported_flash_update_params = DEVLINK_SUPPORT_FLASH_UPDATE_COMPONENT | 1210cbb58368SJacob Keller DEVLINK_SUPPORT_FLASH_UPDATE_OVERWRITE_MASK, 1211ccdf0721SMoshe Shemesh .reload_actions = BIT(DEVLINK_RELOAD_ACTION_DRIVER_REINIT), 121297691069SJiri Pirko .reload_down = nsim_dev_reload_down, 121397691069SJiri Pirko .reload_up = nsim_dev_reload_up, 12148e23cc03SJiri Pirko .info_get = nsim_dev_info_get, 1215fa4dfc4aSJiri Pirko .flash_update = nsim_dev_flash_update, 1216da58f90fSIdo Schimmel .trap_init = nsim_dev_devlink_trap_init, 1217da58f90fSIdo Schimmel .trap_action_set = nsim_dev_devlink_trap_action_set, 12180dc8249aSIdo Schimmel .trap_group_set = nsim_dev_devlink_trap_group_set, 1219ad188458SIdo Schimmel .trap_policer_set = nsim_dev_devlink_trap_policer_set, 1220ad188458SIdo Schimmel .trap_policer_counter_get = nsim_dev_devlink_trap_policer_counter_get, 1221605c4f8fSDmytro Linkin .rate_leaf_tx_share_set = nsim_leaf_tx_share_set, 1222605c4f8fSDmytro Linkin .rate_leaf_tx_max_set = nsim_leaf_tx_max_set, 1223885226f5SDmytro Linkin .rate_node_tx_share_set = nsim_node_tx_share_set, 1224885226f5SDmytro Linkin .rate_node_tx_max_set = nsim_node_tx_max_set, 1225885226f5SDmytro Linkin .rate_node_new = nsim_rate_node_new, 1226885226f5SDmytro Linkin .rate_node_del = nsim_rate_node_del, 1227f3d101b4SDmytro Linkin .rate_leaf_parent_set = nsim_rate_leaf_parent_set, 1228f3d101b4SDmytro Linkin .rate_node_parent_set = nsim_rate_node_parent_set, 12298fb4bc6fSJiri Pirko }; 12308fb4bc6fSJiri Pirko 1231150e8f8aSJiri Pirko #define NSIM_DEV_MAX_MACS_DEFAULT 32 1232150e8f8aSJiri Pirko #define NSIM_DEV_TEST1_DEFAULT true 1233150e8f8aSJiri Pirko 1234814b9ce6SDmytro Linkin static int __nsim_dev_port_add(struct nsim_dev *nsim_dev, enum nsim_dev_port_type type, 1235794b2c05SJiri Pirko unsigned int port_index) 12368320d145SJiri Pirko { 123792ba1f29SDmytro Linkin struct nsim_bus_dev *nsim_bus_dev = nsim_dev->nsim_bus_dev; 123871ad8d55SDanielle Ratson struct devlink_port_attrs attrs = {}; 12398320d145SJiri Pirko struct nsim_dev_port *nsim_dev_port; 12408320d145SJiri Pirko struct devlink_port *devlink_port; 12418320d145SJiri Pirko int err; 12428320d145SJiri Pirko 124392ba1f29SDmytro Linkin if (type == NSIM_DEV_PORT_TYPE_VF && !nsim_bus_dev->num_vfs) 124492ba1f29SDmytro Linkin return -EINVAL; 124592ba1f29SDmytro Linkin 12468320d145SJiri Pirko nsim_dev_port = kzalloc(sizeof(*nsim_dev_port), GFP_KERNEL); 12478320d145SJiri Pirko if (!nsim_dev_port) 12488320d145SJiri Pirko return -ENOMEM; 1249814b9ce6SDmytro Linkin nsim_dev_port->port_index = nsim_dev_port_index(type, port_index); 1250814b9ce6SDmytro Linkin nsim_dev_port->port_type = type; 12518320d145SJiri Pirko 12528320d145SJiri Pirko devlink_port = &nsim_dev_port->devlink_port; 125392ba1f29SDmytro Linkin if (nsim_dev_port_is_pf(nsim_dev_port)) { 125471ad8d55SDanielle Ratson attrs.flavour = DEVLINK_PORT_FLAVOUR_PHYSICAL; 125571ad8d55SDanielle Ratson attrs.phys.port_number = port_index + 1; 125692ba1f29SDmytro Linkin } else { 125792ba1f29SDmytro Linkin attrs.flavour = DEVLINK_PORT_FLAVOUR_PCI_VF; 125892ba1f29SDmytro Linkin attrs.pci_vf.pf = 0; 125992ba1f29SDmytro Linkin attrs.pci_vf.vf = port_index; 126092ba1f29SDmytro Linkin } 126171ad8d55SDanielle Ratson memcpy(attrs.switch_id.id, nsim_dev->switch_id.id, nsim_dev->switch_id.id_len); 126271ad8d55SDanielle Ratson attrs.switch_id.id_len = nsim_dev->switch_id.id_len; 126371ad8d55SDanielle Ratson devlink_port_attrs_set(devlink_port, &attrs); 12648320d145SJiri Pirko err = devlink_port_register(priv_to_devlink(nsim_dev), devlink_port, 1265814b9ce6SDmytro Linkin nsim_dev_port->port_index); 12668320d145SJiri Pirko if (err) 12678320d145SJiri Pirko goto err_port_free; 12688320d145SJiri Pirko 12698320d145SJiri Pirko err = nsim_dev_port_debugfs_init(nsim_dev, nsim_dev_port); 12708320d145SJiri Pirko if (err) 12718320d145SJiri Pirko goto err_dl_port_unregister; 12728320d145SJiri Pirko 1273e05b2d14SJiri Pirko nsim_dev_port->ns = nsim_create(nsim_dev, nsim_dev_port); 1274e05b2d14SJiri Pirko if (IS_ERR(nsim_dev_port->ns)) { 1275e05b2d14SJiri Pirko err = PTR_ERR(nsim_dev_port->ns); 1276e05b2d14SJiri Pirko goto err_port_debugfs_exit; 1277e05b2d14SJiri Pirko } 1278e05b2d14SJiri Pirko 1279885dfe12SDmytro Linkin if (nsim_dev_port_is_vf(nsim_dev_port)) { 1280885dfe12SDmytro Linkin err = devlink_rate_leaf_create(&nsim_dev_port->devlink_port, 1281885dfe12SDmytro Linkin nsim_dev_port); 1282885dfe12SDmytro Linkin if (err) 1283885dfe12SDmytro Linkin goto err_nsim_destroy; 1284885dfe12SDmytro Linkin } 1285885dfe12SDmytro Linkin 1286e05b2d14SJiri Pirko devlink_port_type_eth_set(devlink_port, nsim_dev_port->ns->netdev); 12878320d145SJiri Pirko list_add(&nsim_dev_port->list, &nsim_dev->port_list); 12888320d145SJiri Pirko 12898320d145SJiri Pirko return 0; 12908320d145SJiri Pirko 1291885dfe12SDmytro Linkin err_nsim_destroy: 1292885dfe12SDmytro Linkin nsim_destroy(nsim_dev_port->ns); 1293e05b2d14SJiri Pirko err_port_debugfs_exit: 1294e05b2d14SJiri Pirko nsim_dev_port_debugfs_exit(nsim_dev_port); 12958320d145SJiri Pirko err_dl_port_unregister: 12968320d145SJiri Pirko devlink_port_unregister(devlink_port); 12978320d145SJiri Pirko err_port_free: 12988320d145SJiri Pirko kfree(nsim_dev_port); 12998320d145SJiri Pirko return err; 13008320d145SJiri Pirko } 13018320d145SJiri Pirko 1302794b2c05SJiri Pirko static void __nsim_dev_port_del(struct nsim_dev_port *nsim_dev_port) 13038320d145SJiri Pirko { 13048320d145SJiri Pirko struct devlink_port *devlink_port = &nsim_dev_port->devlink_port; 13058320d145SJiri Pirko 13068320d145SJiri Pirko list_del(&nsim_dev_port->list); 1307885dfe12SDmytro Linkin if (nsim_dev_port_is_vf(nsim_dev_port)) 1308885dfe12SDmytro Linkin devlink_rate_leaf_destroy(&nsim_dev_port->devlink_port); 1309e05b2d14SJiri Pirko devlink_port_type_clear(devlink_port); 1310e05b2d14SJiri Pirko nsim_destroy(nsim_dev_port->ns); 13118320d145SJiri Pirko nsim_dev_port_debugfs_exit(nsim_dev_port); 13128320d145SJiri Pirko devlink_port_unregister(devlink_port); 13138320d145SJiri Pirko kfree(nsim_dev_port); 13148320d145SJiri Pirko } 13158320d145SJiri Pirko 13168320d145SJiri Pirko static void nsim_dev_port_del_all(struct nsim_dev *nsim_dev) 13178320d145SJiri Pirko { 13188320d145SJiri Pirko struct nsim_dev_port *nsim_dev_port, *tmp; 13198320d145SJiri Pirko 13206d6f0383SIdo Schimmel mutex_lock(&nsim_dev->port_list_lock); 13218320d145SJiri Pirko list_for_each_entry_safe(nsim_dev_port, tmp, 13228320d145SJiri Pirko &nsim_dev->port_list, list) 1323794b2c05SJiri Pirko __nsim_dev_port_del(nsim_dev_port); 13246d6f0383SIdo Schimmel mutex_unlock(&nsim_dev->port_list_lock); 13258320d145SJiri Pirko } 13268320d145SJiri Pirko 13277f36a77aSJiri Pirko static int nsim_dev_port_add_all(struct nsim_dev *nsim_dev, 13287f36a77aSJiri Pirko unsigned int port_count) 13298320d145SJiri Pirko { 13307f36a77aSJiri Pirko int i, err; 13318320d145SJiri Pirko 13327f36a77aSJiri Pirko for (i = 0; i < port_count; i++) { 1333814b9ce6SDmytro Linkin err = __nsim_dev_port_add(nsim_dev, NSIM_DEV_PORT_TYPE_PF, i); 13348320d145SJiri Pirko if (err) 13358320d145SJiri Pirko goto err_port_del_all; 13368320d145SJiri Pirko } 13378320d145SJiri Pirko return 0; 13388320d145SJiri Pirko 13398320d145SJiri Pirko err_port_del_all: 13408320d145SJiri Pirko nsim_dev_port_del_all(nsim_dev); 13418320d145SJiri Pirko return err; 13428320d145SJiri Pirko } 13438320d145SJiri Pirko 134475ba029fSJiri Pirko static int nsim_dev_reload_create(struct nsim_dev *nsim_dev, 134575ba029fSJiri Pirko struct netlink_ext_ack *extack) 134675ba029fSJiri Pirko { 134775ba029fSJiri Pirko struct nsim_bus_dev *nsim_bus_dev = nsim_dev->nsim_bus_dev; 134875ba029fSJiri Pirko struct devlink *devlink; 134975ba029fSJiri Pirko int err; 135075ba029fSJiri Pirko 135175ba029fSJiri Pirko devlink = priv_to_devlink(nsim_dev); 135275ba029fSJiri Pirko nsim_dev = devlink_priv(devlink); 135375ba029fSJiri Pirko INIT_LIST_HEAD(&nsim_dev->port_list); 135475ba029fSJiri Pirko mutex_init(&nsim_dev->port_list_lock); 135575ba029fSJiri Pirko nsim_dev->fw_update_status = true; 1356cbb58368SJacob Keller nsim_dev->fw_update_overwrite_mask = 0; 135775ba029fSJiri Pirko 135875ba029fSJiri Pirko nsim_devlink_param_load_driverinit_values(devlink); 135975ba029fSJiri Pirko 136075ba029fSJiri Pirko err = nsim_dev_dummy_region_init(nsim_dev, devlink); 136175ba029fSJiri Pirko if (err) 1362f57ab5b7SIdo Schimmel return err; 136375ba029fSJiri Pirko 136475ba029fSJiri Pirko err = nsim_dev_traps_init(devlink); 136575ba029fSJiri Pirko if (err) 136675ba029fSJiri Pirko goto err_dummy_region_exit; 136775ba029fSJiri Pirko 1368f57ab5b7SIdo Schimmel nsim_dev->fib_data = nsim_fib_create(devlink, extack); 1369f57ab5b7SIdo Schimmel if (IS_ERR(nsim_dev->fib_data)) { 1370f57ab5b7SIdo Schimmel err = PTR_ERR(nsim_dev->fib_data); 1371f57ab5b7SIdo Schimmel goto err_traps_exit; 1372f57ab5b7SIdo Schimmel } 1373f57ab5b7SIdo Schimmel 137482c93a87SJiri Pirko err = nsim_dev_health_init(nsim_dev, devlink); 137575ba029fSJiri Pirko if (err) 1376f57ab5b7SIdo Schimmel goto err_fib_destroy; 137775ba029fSJiri Pirko 1378a8700c3dSIdo Schimmel err = nsim_dev_psample_init(nsim_dev); 137982c93a87SJiri Pirko if (err) 138082c93a87SJiri Pirko goto err_health_exit; 138182c93a87SJiri Pirko 1382a8700c3dSIdo Schimmel err = nsim_dev_port_add_all(nsim_dev, nsim_bus_dev->port_count); 1383a8700c3dSIdo Schimmel if (err) 1384a8700c3dSIdo Schimmel goto err_psample_exit; 1385a8700c3dSIdo Schimmel 13868526ad96STaehee Yoo nsim_dev->take_snapshot = debugfs_create_file("take_snapshot", 13878526ad96STaehee Yoo 0200, 13888526ad96STaehee Yoo nsim_dev->ddir, 13898526ad96STaehee Yoo nsim_dev, 13908526ad96STaehee Yoo &nsim_dev_take_snapshot_fops); 139175ba029fSJiri Pirko return 0; 139275ba029fSJiri Pirko 1393a8700c3dSIdo Schimmel err_psample_exit: 1394a8700c3dSIdo Schimmel nsim_dev_psample_exit(nsim_dev); 139582c93a87SJiri Pirko err_health_exit: 139682c93a87SJiri Pirko nsim_dev_health_exit(nsim_dev); 1397f57ab5b7SIdo Schimmel err_fib_destroy: 1398f57ab5b7SIdo Schimmel nsim_fib_destroy(devlink, nsim_dev->fib_data); 139975ba029fSJiri Pirko err_traps_exit: 140075ba029fSJiri Pirko nsim_dev_traps_exit(devlink); 140175ba029fSJiri Pirko err_dummy_region_exit: 140275ba029fSJiri Pirko nsim_dev_dummy_region_exit(nsim_dev); 140375ba029fSJiri Pirko return err; 140475ba029fSJiri Pirko } 140575ba029fSJiri Pirko 1406bfcccfe7SJakub Kicinski int nsim_dev_probe(struct nsim_bus_dev *nsim_bus_dev) 14077f36a77aSJiri Pirko { 14087f36a77aSJiri Pirko struct nsim_dev *nsim_dev; 14097f36a77aSJiri Pirko struct devlink *devlink; 14107f36a77aSJiri Pirko int err; 14117f36a77aSJiri Pirko 14127f36a77aSJiri Pirko devlink = devlink_alloc(&nsim_dev_devlink_ops, sizeof(*nsim_dev)); 14137f36a77aSJiri Pirko if (!devlink) 1414bfcccfe7SJakub Kicinski return -ENOMEM; 14157b60027bSJiri Pirko devlink_net_set(devlink, nsim_bus_dev->initial_net); 14167f36a77aSJiri Pirko nsim_dev = devlink_priv(devlink); 14177f36a77aSJiri Pirko nsim_dev->nsim_bus_dev = nsim_bus_dev; 14187f36a77aSJiri Pirko nsim_dev->switch_id.id_len = sizeof(nsim_dev->switch_id.id); 14197f36a77aSJiri Pirko get_random_bytes(nsim_dev->switch_id.id, nsim_dev->switch_id.id_len); 14207f36a77aSJiri Pirko INIT_LIST_HEAD(&nsim_dev->port_list); 14217f36a77aSJiri Pirko mutex_init(&nsim_dev->port_list_lock); 14227f36a77aSJiri Pirko nsim_dev->fw_update_status = true; 1423cbb58368SJacob Keller nsim_dev->fw_update_overwrite_mask = 0; 14247f36a77aSJiri Pirko nsim_dev->max_macs = NSIM_DEV_MAX_MACS_DEFAULT; 14257f36a77aSJiri Pirko nsim_dev->test1 = NSIM_DEV_TEST1_DEFAULT; 1426d3cbb907SJiri Pirko spin_lock_init(&nsim_dev->fa_cookie_lock); 14277f36a77aSJiri Pirko 1428bfcccfe7SJakub Kicinski dev_set_drvdata(&nsim_bus_dev->dev, nsim_dev); 1429bfcccfe7SJakub Kicinski 14307f36a77aSJiri Pirko err = nsim_dev_resources_register(devlink); 14317f36a77aSJiri Pirko if (err) 14327f36a77aSJiri Pirko goto err_devlink_free; 14337f36a77aSJiri Pirko 14347f36a77aSJiri Pirko err = devlink_register(devlink, &nsim_bus_dev->dev); 14357f36a77aSJiri Pirko if (err) 1436f57ab5b7SIdo Schimmel goto err_resources_unregister; 14377f36a77aSJiri Pirko 14387f36a77aSJiri Pirko err = devlink_params_register(devlink, nsim_devlink_params, 14397f36a77aSJiri Pirko ARRAY_SIZE(nsim_devlink_params)); 14407f36a77aSJiri Pirko if (err) 14417f36a77aSJiri Pirko goto err_dl_unregister; 14427f36a77aSJiri Pirko nsim_devlink_set_params_init_values(nsim_dev, devlink); 14437f36a77aSJiri Pirko 14447f36a77aSJiri Pirko err = nsim_dev_dummy_region_init(nsim_dev, devlink); 14457f36a77aSJiri Pirko if (err) 14467f36a77aSJiri Pirko goto err_params_unregister; 14477f36a77aSJiri Pirko 14487f36a77aSJiri Pirko err = nsim_dev_traps_init(devlink); 14497f36a77aSJiri Pirko if (err) 14507f36a77aSJiri Pirko goto err_dummy_region_exit; 14517f36a77aSJiri Pirko 14527f36a77aSJiri Pirko err = nsim_dev_debugfs_init(nsim_dev); 14537f36a77aSJiri Pirko if (err) 14547f36a77aSJiri Pirko goto err_traps_exit; 14557f36a77aSJiri Pirko 1456f57ab5b7SIdo Schimmel nsim_dev->fib_data = nsim_fib_create(devlink, NULL); 1457f57ab5b7SIdo Schimmel if (IS_ERR(nsim_dev->fib_data)) { 1458f57ab5b7SIdo Schimmel err = PTR_ERR(nsim_dev->fib_data); 1459f57ab5b7SIdo Schimmel goto err_debugfs_exit; 1460f57ab5b7SIdo Schimmel } 1461f57ab5b7SIdo Schimmel 146282c93a87SJiri Pirko err = nsim_dev_health_init(nsim_dev, devlink); 14637f36a77aSJiri Pirko if (err) 1464f57ab5b7SIdo Schimmel goto err_fib_destroy; 14657f36a77aSJiri Pirko 146682c93a87SJiri Pirko err = nsim_bpf_dev_init(nsim_dev); 146782c93a87SJiri Pirko if (err) 146882c93a87SJiri Pirko goto err_health_exit; 146982c93a87SJiri Pirko 1470a8700c3dSIdo Schimmel err = nsim_dev_psample_init(nsim_dev); 14717f36a77aSJiri Pirko if (err) 14727f36a77aSJiri Pirko goto err_bpf_dev_exit; 14737f36a77aSJiri Pirko 1474a8700c3dSIdo Schimmel err = nsim_dev_port_add_all(nsim_dev, nsim_bus_dev->port_count); 1475a8700c3dSIdo Schimmel if (err) 1476a8700c3dSIdo Schimmel goto err_psample_exit; 1477a8700c3dSIdo Schimmel 14787f36a77aSJiri Pirko devlink_params_publish(devlink); 1479a0c76345SJiri Pirko devlink_reload_enable(devlink); 1480160dc373SDmytro Linkin nsim_dev->esw_mode = DEVLINK_ESWITCH_MODE_LEGACY; 1481bfcccfe7SJakub Kicinski return 0; 14827f36a77aSJiri Pirko 1483a8700c3dSIdo Schimmel err_psample_exit: 1484a8700c3dSIdo Schimmel nsim_dev_psample_exit(nsim_dev); 14857f36a77aSJiri Pirko err_bpf_dev_exit: 14867f36a77aSJiri Pirko nsim_bpf_dev_exit(nsim_dev); 148782c93a87SJiri Pirko err_health_exit: 148882c93a87SJiri Pirko nsim_dev_health_exit(nsim_dev); 1489f57ab5b7SIdo Schimmel err_fib_destroy: 1490f57ab5b7SIdo Schimmel nsim_fib_destroy(devlink, nsim_dev->fib_data); 14917f36a77aSJiri Pirko err_debugfs_exit: 14927f36a77aSJiri Pirko nsim_dev_debugfs_exit(nsim_dev); 14937f36a77aSJiri Pirko err_traps_exit: 14947f36a77aSJiri Pirko nsim_dev_traps_exit(devlink); 14957f36a77aSJiri Pirko err_dummy_region_exit: 14967f36a77aSJiri Pirko nsim_dev_dummy_region_exit(nsim_dev); 14977f36a77aSJiri Pirko err_params_unregister: 14987f36a77aSJiri Pirko devlink_params_unregister(devlink, nsim_devlink_params, 14997f36a77aSJiri Pirko ARRAY_SIZE(nsim_devlink_params)); 15007f36a77aSJiri Pirko err_dl_unregister: 15017f36a77aSJiri Pirko devlink_unregister(devlink); 15027f36a77aSJiri Pirko err_resources_unregister: 15037f36a77aSJiri Pirko devlink_resources_unregister(devlink, NULL); 15047f36a77aSJiri Pirko err_devlink_free: 15057f36a77aSJiri Pirko devlink_free(devlink); 1506bfcccfe7SJakub Kicinski return err; 15077f36a77aSJiri Pirko } 15087f36a77aSJiri Pirko 150975ba029fSJiri Pirko static void nsim_dev_reload_destroy(struct nsim_dev *nsim_dev) 151075ba029fSJiri Pirko { 151175ba029fSJiri Pirko struct devlink *devlink = priv_to_devlink(nsim_dev); 151275ba029fSJiri Pirko 151375ba029fSJiri Pirko if (devlink_is_reload_failed(devlink)) 151475ba029fSJiri Pirko return; 15158526ad96STaehee Yoo debugfs_remove(nsim_dev->take_snapshot); 151632ac15d8SDmytro Linkin 151732ac15d8SDmytro Linkin mutex_lock(&nsim_dev->nsim_bus_dev->vfs_lock); 151832ac15d8SDmytro Linkin if (nsim_dev->nsim_bus_dev->num_vfs) 151932ac15d8SDmytro Linkin nsim_bus_dev_vfs_disable(nsim_dev->nsim_bus_dev); 152032ac15d8SDmytro Linkin mutex_unlock(&nsim_dev->nsim_bus_dev->vfs_lock); 152132ac15d8SDmytro Linkin 152275ba029fSJiri Pirko nsim_dev_port_del_all(nsim_dev); 1523a8700c3dSIdo Schimmel nsim_dev_psample_exit(nsim_dev); 152482c93a87SJiri Pirko nsim_dev_health_exit(nsim_dev); 1525f57ab5b7SIdo Schimmel nsim_fib_destroy(devlink, nsim_dev->fib_data); 152675ba029fSJiri Pirko nsim_dev_traps_exit(devlink); 152775ba029fSJiri Pirko nsim_dev_dummy_region_exit(nsim_dev); 152875ba029fSJiri Pirko mutex_destroy(&nsim_dev->port_list_lock); 152975ba029fSJiri Pirko } 153075ba029fSJiri Pirko 1531bfcccfe7SJakub Kicinski void nsim_dev_remove(struct nsim_bus_dev *nsim_bus_dev) 15327f36a77aSJiri Pirko { 1533bfcccfe7SJakub Kicinski struct nsim_dev *nsim_dev = dev_get_drvdata(&nsim_bus_dev->dev); 15347f36a77aSJiri Pirko struct devlink *devlink = priv_to_devlink(nsim_dev); 15357f36a77aSJiri Pirko 1536a0c76345SJiri Pirko devlink_reload_disable(devlink); 1537a0c76345SJiri Pirko 153875ba029fSJiri Pirko nsim_dev_reload_destroy(nsim_dev); 153975ba029fSJiri Pirko 15407f36a77aSJiri Pirko nsim_bpf_dev_exit(nsim_dev); 15417f36a77aSJiri Pirko nsim_dev_debugfs_exit(nsim_dev); 15427f36a77aSJiri Pirko devlink_params_unregister(devlink, nsim_devlink_params, 15437f36a77aSJiri Pirko ARRAY_SIZE(nsim_devlink_params)); 15447f36a77aSJiri Pirko devlink_unregister(devlink); 15457f36a77aSJiri Pirko devlink_resources_unregister(devlink, NULL); 15467f36a77aSJiri Pirko devlink_free(devlink); 15477f36a77aSJiri Pirko } 15487f36a77aSJiri Pirko 1549794b2c05SJiri Pirko static struct nsim_dev_port * 1550814b9ce6SDmytro Linkin __nsim_dev_port_lookup(struct nsim_dev *nsim_dev, enum nsim_dev_port_type type, 1551814b9ce6SDmytro Linkin unsigned int port_index) 1552794b2c05SJiri Pirko { 1553794b2c05SJiri Pirko struct nsim_dev_port *nsim_dev_port; 1554794b2c05SJiri Pirko 1555814b9ce6SDmytro Linkin port_index = nsim_dev_port_index(type, port_index); 1556794b2c05SJiri Pirko list_for_each_entry(nsim_dev_port, &nsim_dev->port_list, list) 1557794b2c05SJiri Pirko if (nsim_dev_port->port_index == port_index) 1558794b2c05SJiri Pirko return nsim_dev_port; 1559794b2c05SJiri Pirko return NULL; 1560794b2c05SJiri Pirko } 1561794b2c05SJiri Pirko 1562814b9ce6SDmytro Linkin int nsim_dev_port_add(struct nsim_bus_dev *nsim_bus_dev, enum nsim_dev_port_type type, 1563794b2c05SJiri Pirko unsigned int port_index) 1564794b2c05SJiri Pirko { 1565794b2c05SJiri Pirko struct nsim_dev *nsim_dev = dev_get_drvdata(&nsim_bus_dev->dev); 1566794b2c05SJiri Pirko int err; 1567794b2c05SJiri Pirko 1568794b2c05SJiri Pirko mutex_lock(&nsim_dev->port_list_lock); 1569814b9ce6SDmytro Linkin if (__nsim_dev_port_lookup(nsim_dev, type, port_index)) 1570794b2c05SJiri Pirko err = -EEXIST; 1571794b2c05SJiri Pirko else 1572814b9ce6SDmytro Linkin err = __nsim_dev_port_add(nsim_dev, type, port_index); 1573794b2c05SJiri Pirko mutex_unlock(&nsim_dev->port_list_lock); 1574794b2c05SJiri Pirko return err; 1575794b2c05SJiri Pirko } 1576794b2c05SJiri Pirko 1577814b9ce6SDmytro Linkin int nsim_dev_port_del(struct nsim_bus_dev *nsim_bus_dev, enum nsim_dev_port_type type, 1578794b2c05SJiri Pirko unsigned int port_index) 1579794b2c05SJiri Pirko { 1580794b2c05SJiri Pirko struct nsim_dev *nsim_dev = dev_get_drvdata(&nsim_bus_dev->dev); 1581794b2c05SJiri Pirko struct nsim_dev_port *nsim_dev_port; 1582794b2c05SJiri Pirko int err = 0; 1583794b2c05SJiri Pirko 1584794b2c05SJiri Pirko mutex_lock(&nsim_dev->port_list_lock); 1585814b9ce6SDmytro Linkin nsim_dev_port = __nsim_dev_port_lookup(nsim_dev, type, port_index); 1586794b2c05SJiri Pirko if (!nsim_dev_port) 1587794b2c05SJiri Pirko err = -ENOENT; 1588794b2c05SJiri Pirko else 1589794b2c05SJiri Pirko __nsim_dev_port_del(nsim_dev_port); 1590794b2c05SJiri Pirko mutex_unlock(&nsim_dev->port_list_lock); 1591794b2c05SJiri Pirko return err; 1592794b2c05SJiri Pirko } 1593794b2c05SJiri Pirko 1594d514f41eSJiri Pirko int nsim_dev_init(void) 1595d514f41eSJiri Pirko { 1596ab1d0cc0SJiri Pirko nsim_dev_ddir = debugfs_create_dir(DRV_NAME, NULL); 159734611e69Skbuild test robot return PTR_ERR_OR_ZERO(nsim_dev_ddir); 1598d514f41eSJiri Pirko } 1599d514f41eSJiri Pirko 1600d514f41eSJiri Pirko void nsim_dev_exit(void) 1601d514f41eSJiri Pirko { 1602d514f41eSJiri Pirko debugfs_remove_recursive(nsim_dev_ddir); 1603d514f41eSJiri Pirko } 1604