root/drivers/net/netdevsim/dev.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. nsim_dev_take_snapshot_write
  2. nsim_dev_debugfs_init
  3. nsim_dev_debugfs_exit
  4. nsim_dev_port_debugfs_init
  5. nsim_dev_port_debugfs_exit
  6. nsim_devlink_net
  7. nsim_dev_ipv4_fib_resource_occ_get
  8. nsim_dev_ipv4_fib_rules_res_occ_get
  9. nsim_dev_ipv6_fib_resource_occ_get
  10. nsim_dev_ipv6_fib_rules_res_occ_get
  11. nsim_dev_resources_register
  12. nsim_devlink_set_params_init_values
  13. nsim_devlink_param_load_driverinit_values
  14. nsim_dev_dummy_region_init
  15. nsim_dev_dummy_region_exit
  16. nsim_dev_trap_skb_build
  17. nsim_dev_trap_report
  18. nsim_dev_trap_report_work
  19. nsim_dev_traps_init
  20. nsim_dev_traps_exit
  21. nsim_dev_reload_down
  22. nsim_dev_reload_up
  23. nsim_dev_flash_update
  24. nsim_dev_trap_item_lookup
  25. nsim_dev_devlink_trap_init
  26. nsim_dev_devlink_trap_action_set
  27. nsim_dev_create
  28. nsim_dev_destroy
  29. __nsim_dev_port_add
  30. __nsim_dev_port_del
  31. nsim_dev_port_del_all
  32. nsim_dev_probe
  33. nsim_dev_remove
  34. __nsim_dev_port_lookup
  35. nsim_dev_port_add
  36. nsim_dev_port_del
  37. nsim_dev_init
  38. nsim_dev_exit

   1 /*
   2  * Copyright (c) 2018 Cumulus Networks. All rights reserved.
   3  * Copyright (c) 2018 David Ahern <dsa@cumulusnetworks.com>
   4  * Copyright (c) 2019 Mellanox Technologies. All rights reserved.
   5  *
   6  * This software is licensed under the GNU General License Version 2,
   7  * June 1991 as shown in the file COPYING in the top-level directory of this
   8  * source tree.
   9  *
  10  * THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS"
  11  * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
  12  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  13  * FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE
  14  * OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME
  15  * THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
  16  */
  17 
  18 #include <linux/debugfs.h>
  19 #include <linux/device.h>
  20 #include <linux/etherdevice.h>
  21 #include <linux/inet.h>
  22 #include <linux/jiffies.h>
  23 #include <linux/kernel.h>
  24 #include <linux/list.h>
  25 #include <linux/mutex.h>
  26 #include <linux/random.h>
  27 #include <linux/rtnetlink.h>
  28 #include <linux/workqueue.h>
  29 #include <net/devlink.h>
  30 #include <net/ip.h>
  31 #include <uapi/linux/devlink.h>
  32 #include <uapi/linux/ip.h>
  33 #include <uapi/linux/udp.h>
  34 
  35 #include "netdevsim.h"
  36 
  37 static struct dentry *nsim_dev_ddir;
  38 
  39 #define NSIM_DEV_DUMMY_REGION_SIZE (1024 * 32)
  40 
  41 static ssize_t nsim_dev_take_snapshot_write(struct file *file,
  42                                             const char __user *data,
  43                                             size_t count, loff_t *ppos)
  44 {
  45         struct nsim_dev *nsim_dev = file->private_data;
  46         void *dummy_data;
  47         int err;
  48         u32 id;
  49 
  50         dummy_data = kmalloc(NSIM_DEV_DUMMY_REGION_SIZE, GFP_KERNEL);
  51         if (!dummy_data)
  52                 return -ENOMEM;
  53 
  54         get_random_bytes(dummy_data, NSIM_DEV_DUMMY_REGION_SIZE);
  55 
  56         id = devlink_region_shapshot_id_get(priv_to_devlink(nsim_dev));
  57         err = devlink_region_snapshot_create(nsim_dev->dummy_region,
  58                                              dummy_data, id, kfree);
  59         if (err) {
  60                 pr_err("Failed to create region snapshot\n");
  61                 kfree(dummy_data);
  62                 return err;
  63         }
  64 
  65         return count;
  66 }
  67 
  68 static const struct file_operations nsim_dev_take_snapshot_fops = {
  69         .open = simple_open,
  70         .write = nsim_dev_take_snapshot_write,
  71         .llseek = generic_file_llseek,
  72 };
  73 
  74 static int nsim_dev_debugfs_init(struct nsim_dev *nsim_dev)
  75 {
  76         char dev_ddir_name[sizeof(DRV_NAME) + 10];
  77 
  78         sprintf(dev_ddir_name, DRV_NAME "%u", nsim_dev->nsim_bus_dev->dev.id);
  79         nsim_dev->ddir = debugfs_create_dir(dev_ddir_name, nsim_dev_ddir);
  80         if (IS_ERR_OR_NULL(nsim_dev->ddir))
  81                 return PTR_ERR_OR_ZERO(nsim_dev->ddir) ?: -EINVAL;
  82         nsim_dev->ports_ddir = debugfs_create_dir("ports", nsim_dev->ddir);
  83         if (IS_ERR_OR_NULL(nsim_dev->ports_ddir))
  84                 return PTR_ERR_OR_ZERO(nsim_dev->ports_ddir) ?: -EINVAL;
  85         debugfs_create_bool("fw_update_status", 0600, nsim_dev->ddir,
  86                             &nsim_dev->fw_update_status);
  87         debugfs_create_u32("max_macs", 0600, nsim_dev->ddir,
  88                            &nsim_dev->max_macs);
  89         debugfs_create_bool("test1", 0600, nsim_dev->ddir,
  90                             &nsim_dev->test1);
  91         debugfs_create_file("take_snapshot", 0200, nsim_dev->ddir, nsim_dev,
  92                             &nsim_dev_take_snapshot_fops);
  93         return 0;
  94 }
  95 
  96 static void nsim_dev_debugfs_exit(struct nsim_dev *nsim_dev)
  97 {
  98         debugfs_remove_recursive(nsim_dev->ports_ddir);
  99         debugfs_remove_recursive(nsim_dev->ddir);
 100 }
 101 
 102 static int nsim_dev_port_debugfs_init(struct nsim_dev *nsim_dev,
 103                                       struct nsim_dev_port *nsim_dev_port)
 104 {
 105         char port_ddir_name[16];
 106         char dev_link_name[32];
 107 
 108         sprintf(port_ddir_name, "%u", nsim_dev_port->port_index);
 109         nsim_dev_port->ddir = debugfs_create_dir(port_ddir_name,
 110                                                  nsim_dev->ports_ddir);
 111         if (IS_ERR_OR_NULL(nsim_dev_port->ddir))
 112                 return -ENOMEM;
 113 
 114         sprintf(dev_link_name, "../../../" DRV_NAME "%u",
 115                 nsim_dev->nsim_bus_dev->dev.id);
 116         debugfs_create_symlink("dev", nsim_dev_port->ddir, dev_link_name);
 117 
 118         return 0;
 119 }
 120 
 121 static void nsim_dev_port_debugfs_exit(struct nsim_dev_port *nsim_dev_port)
 122 {
 123         debugfs_remove_recursive(nsim_dev_port->ddir);
 124 }
 125 
 126 static struct net *nsim_devlink_net(struct devlink *devlink)
 127 {
 128         return &init_net;
 129 }
 130 
 131 static u64 nsim_dev_ipv4_fib_resource_occ_get(void *priv)
 132 {
 133         struct net *net = priv;
 134 
 135         return nsim_fib_get_val(net, NSIM_RESOURCE_IPV4_FIB, false);
 136 }
 137 
 138 static u64 nsim_dev_ipv4_fib_rules_res_occ_get(void *priv)
 139 {
 140         struct net *net = priv;
 141 
 142         return nsim_fib_get_val(net, NSIM_RESOURCE_IPV4_FIB_RULES, false);
 143 }
 144 
 145 static u64 nsim_dev_ipv6_fib_resource_occ_get(void *priv)
 146 {
 147         struct net *net = priv;
 148 
 149         return nsim_fib_get_val(net, NSIM_RESOURCE_IPV6_FIB, false);
 150 }
 151 
 152 static u64 nsim_dev_ipv6_fib_rules_res_occ_get(void *priv)
 153 {
 154         struct net *net = priv;
 155 
 156         return nsim_fib_get_val(net, NSIM_RESOURCE_IPV6_FIB_RULES, false);
 157 }
 158 
 159 static int nsim_dev_resources_register(struct devlink *devlink)
 160 {
 161         struct devlink_resource_size_params params = {
 162                 .size_max = (u64)-1,
 163                 .size_granularity = 1,
 164                 .unit = DEVLINK_RESOURCE_UNIT_ENTRY
 165         };
 166         struct net *net = nsim_devlink_net(devlink);
 167         int err;
 168         u64 n;
 169 
 170         /* Resources for IPv4 */
 171         err = devlink_resource_register(devlink, "IPv4", (u64)-1,
 172                                         NSIM_RESOURCE_IPV4,
 173                                         DEVLINK_RESOURCE_ID_PARENT_TOP,
 174                                         &params);
 175         if (err) {
 176                 pr_err("Failed to register IPv4 top resource\n");
 177                 goto out;
 178         }
 179 
 180         n = nsim_fib_get_val(net, NSIM_RESOURCE_IPV4_FIB, true);
 181         err = devlink_resource_register(devlink, "fib", n,
 182                                         NSIM_RESOURCE_IPV4_FIB,
 183                                         NSIM_RESOURCE_IPV4, &params);
 184         if (err) {
 185                 pr_err("Failed to register IPv4 FIB resource\n");
 186                 return err;
 187         }
 188 
 189         n = nsim_fib_get_val(net, NSIM_RESOURCE_IPV4_FIB_RULES, true);
 190         err = devlink_resource_register(devlink, "fib-rules", n,
 191                                         NSIM_RESOURCE_IPV4_FIB_RULES,
 192                                         NSIM_RESOURCE_IPV4, &params);
 193         if (err) {
 194                 pr_err("Failed to register IPv4 FIB rules resource\n");
 195                 return err;
 196         }
 197 
 198         /* Resources for IPv6 */
 199         err = devlink_resource_register(devlink, "IPv6", (u64)-1,
 200                                         NSIM_RESOURCE_IPV6,
 201                                         DEVLINK_RESOURCE_ID_PARENT_TOP,
 202                                         &params);
 203         if (err) {
 204                 pr_err("Failed to register IPv6 top resource\n");
 205                 goto out;
 206         }
 207 
 208         n = nsim_fib_get_val(net, NSIM_RESOURCE_IPV6_FIB, true);
 209         err = devlink_resource_register(devlink, "fib", n,
 210                                         NSIM_RESOURCE_IPV6_FIB,
 211                                         NSIM_RESOURCE_IPV6, &params);
 212         if (err) {
 213                 pr_err("Failed to register IPv6 FIB resource\n");
 214                 return err;
 215         }
 216 
 217         n = nsim_fib_get_val(net, NSIM_RESOURCE_IPV6_FIB_RULES, true);
 218         err = devlink_resource_register(devlink, "fib-rules", n,
 219                                         NSIM_RESOURCE_IPV6_FIB_RULES,
 220                                         NSIM_RESOURCE_IPV6, &params);
 221         if (err) {
 222                 pr_err("Failed to register IPv6 FIB rules resource\n");
 223                 return err;
 224         }
 225 
 226         devlink_resource_occ_get_register(devlink,
 227                                           NSIM_RESOURCE_IPV4_FIB,
 228                                           nsim_dev_ipv4_fib_resource_occ_get,
 229                                           net);
 230         devlink_resource_occ_get_register(devlink,
 231                                           NSIM_RESOURCE_IPV4_FIB_RULES,
 232                                           nsim_dev_ipv4_fib_rules_res_occ_get,
 233                                           net);
 234         devlink_resource_occ_get_register(devlink,
 235                                           NSIM_RESOURCE_IPV6_FIB,
 236                                           nsim_dev_ipv6_fib_resource_occ_get,
 237                                           net);
 238         devlink_resource_occ_get_register(devlink,
 239                                           NSIM_RESOURCE_IPV6_FIB_RULES,
 240                                           nsim_dev_ipv6_fib_rules_res_occ_get,
 241                                           net);
 242 out:
 243         return err;
 244 }
 245 
 246 enum nsim_devlink_param_id {
 247         NSIM_DEVLINK_PARAM_ID_BASE = DEVLINK_PARAM_GENERIC_ID_MAX,
 248         NSIM_DEVLINK_PARAM_ID_TEST1,
 249 };
 250 
 251 static const struct devlink_param nsim_devlink_params[] = {
 252         DEVLINK_PARAM_GENERIC(MAX_MACS,
 253                               BIT(DEVLINK_PARAM_CMODE_DRIVERINIT),
 254                               NULL, NULL, NULL),
 255         DEVLINK_PARAM_DRIVER(NSIM_DEVLINK_PARAM_ID_TEST1,
 256                              "test1", DEVLINK_PARAM_TYPE_BOOL,
 257                              BIT(DEVLINK_PARAM_CMODE_DRIVERINIT),
 258                              NULL, NULL, NULL),
 259 };
 260 
 261 static void nsim_devlink_set_params_init_values(struct nsim_dev *nsim_dev,
 262                                                 struct devlink *devlink)
 263 {
 264         union devlink_param_value value;
 265 
 266         value.vu32 = nsim_dev->max_macs;
 267         devlink_param_driverinit_value_set(devlink,
 268                                            DEVLINK_PARAM_GENERIC_ID_MAX_MACS,
 269                                            value);
 270         value.vbool = nsim_dev->test1;
 271         devlink_param_driverinit_value_set(devlink,
 272                                            NSIM_DEVLINK_PARAM_ID_TEST1,
 273                                            value);
 274 }
 275 
 276 static void nsim_devlink_param_load_driverinit_values(struct devlink *devlink)
 277 {
 278         struct nsim_dev *nsim_dev = devlink_priv(devlink);
 279         union devlink_param_value saved_value;
 280         int err;
 281 
 282         err = devlink_param_driverinit_value_get(devlink,
 283                                                  DEVLINK_PARAM_GENERIC_ID_MAX_MACS,
 284                                                  &saved_value);
 285         if (!err)
 286                 nsim_dev->max_macs = saved_value.vu32;
 287         err = devlink_param_driverinit_value_get(devlink,
 288                                                  NSIM_DEVLINK_PARAM_ID_TEST1,
 289                                                  &saved_value);
 290         if (!err)
 291                 nsim_dev->test1 = saved_value.vbool;
 292 }
 293 
 294 #define NSIM_DEV_DUMMY_REGION_SNAPSHOT_MAX 16
 295 
 296 static int nsim_dev_dummy_region_init(struct nsim_dev *nsim_dev,
 297                                       struct devlink *devlink)
 298 {
 299         nsim_dev->dummy_region =
 300                 devlink_region_create(devlink, "dummy",
 301                                       NSIM_DEV_DUMMY_REGION_SNAPSHOT_MAX,
 302                                       NSIM_DEV_DUMMY_REGION_SIZE);
 303         return PTR_ERR_OR_ZERO(nsim_dev->dummy_region);
 304 }
 305 
 306 static void nsim_dev_dummy_region_exit(struct nsim_dev *nsim_dev)
 307 {
 308         devlink_region_destroy(nsim_dev->dummy_region);
 309 }
 310 
 311 struct nsim_trap_item {
 312         void *trap_ctx;
 313         enum devlink_trap_action action;
 314 };
 315 
 316 struct nsim_trap_data {
 317         struct delayed_work trap_report_dw;
 318         struct nsim_trap_item *trap_items_arr;
 319         struct nsim_dev *nsim_dev;
 320         spinlock_t trap_lock;   /* Protects trap_items_arr */
 321 };
 322 
 323 /* All driver-specific traps must be documented in
 324  * Documentation/networking/devlink-trap-netdevsim.rst
 325  */
 326 enum {
 327         NSIM_TRAP_ID_BASE = DEVLINK_TRAP_GENERIC_ID_MAX,
 328         NSIM_TRAP_ID_FID_MISS,
 329 };
 330 
 331 #define NSIM_TRAP_NAME_FID_MISS "fid_miss"
 332 
 333 #define NSIM_TRAP_METADATA DEVLINK_TRAP_METADATA_TYPE_F_IN_PORT
 334 
 335 #define NSIM_TRAP_DROP(_id, _group_id)                                        \
 336         DEVLINK_TRAP_GENERIC(DROP, DROP, _id,                                 \
 337                              DEVLINK_TRAP_GROUP_GENERIC(_group_id),           \
 338                              NSIM_TRAP_METADATA)
 339 #define NSIM_TRAP_EXCEPTION(_id, _group_id)                                   \
 340         DEVLINK_TRAP_GENERIC(EXCEPTION, TRAP, _id,                            \
 341                              DEVLINK_TRAP_GROUP_GENERIC(_group_id),           \
 342                              NSIM_TRAP_METADATA)
 343 #define NSIM_TRAP_DRIVER_EXCEPTION(_id, _group_id)                            \
 344         DEVLINK_TRAP_DRIVER(EXCEPTION, TRAP, NSIM_TRAP_ID_##_id,              \
 345                             NSIM_TRAP_NAME_##_id,                             \
 346                             DEVLINK_TRAP_GROUP_GENERIC(_group_id),            \
 347                             NSIM_TRAP_METADATA)
 348 
 349 static const struct devlink_trap nsim_traps_arr[] = {
 350         NSIM_TRAP_DROP(SMAC_MC, L2_DROPS),
 351         NSIM_TRAP_DROP(VLAN_TAG_MISMATCH, L2_DROPS),
 352         NSIM_TRAP_DROP(INGRESS_VLAN_FILTER, L2_DROPS),
 353         NSIM_TRAP_DROP(INGRESS_STP_FILTER, L2_DROPS),
 354         NSIM_TRAP_DROP(EMPTY_TX_LIST, L2_DROPS),
 355         NSIM_TRAP_DROP(PORT_LOOPBACK_FILTER, L2_DROPS),
 356         NSIM_TRAP_DRIVER_EXCEPTION(FID_MISS, L2_DROPS),
 357         NSIM_TRAP_DROP(BLACKHOLE_ROUTE, L3_DROPS),
 358         NSIM_TRAP_EXCEPTION(TTL_ERROR, L3_DROPS),
 359         NSIM_TRAP_DROP(TAIL_DROP, BUFFER_DROPS),
 360 };
 361 
 362 #define NSIM_TRAP_L4_DATA_LEN 100
 363 
 364 static struct sk_buff *nsim_dev_trap_skb_build(void)
 365 {
 366         int tot_len, data_len = NSIM_TRAP_L4_DATA_LEN;
 367         struct sk_buff *skb;
 368         struct udphdr *udph;
 369         struct ethhdr *eth;
 370         struct iphdr *iph;
 371 
 372         skb = alloc_skb(NLMSG_GOODSIZE, GFP_ATOMIC);
 373         if (!skb)
 374                 return NULL;
 375         tot_len = sizeof(struct iphdr) + sizeof(struct udphdr) + data_len;
 376 
 377         skb_reset_mac_header(skb);
 378         eth = skb_put(skb, sizeof(struct ethhdr));
 379         eth_random_addr(eth->h_dest);
 380         eth_random_addr(eth->h_source);
 381         eth->h_proto = htons(ETH_P_IP);
 382         skb->protocol = htons(ETH_P_IP);
 383 
 384         skb_set_network_header(skb, skb->len);
 385         iph = skb_put(skb, sizeof(struct iphdr));
 386         iph->protocol = IPPROTO_UDP;
 387         iph->saddr = in_aton("192.0.2.1");
 388         iph->daddr = in_aton("198.51.100.1");
 389         iph->version = 0x4;
 390         iph->frag_off = 0;
 391         iph->ihl = 0x5;
 392         iph->tot_len = htons(tot_len);
 393         iph->ttl = 100;
 394         iph->check = 0;
 395         iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
 396 
 397         skb_set_transport_header(skb, skb->len);
 398         udph = skb_put_zero(skb, sizeof(struct udphdr) + data_len);
 399         get_random_bytes(&udph->source, sizeof(u16));
 400         get_random_bytes(&udph->dest, sizeof(u16));
 401         udph->len = htons(sizeof(struct udphdr) + data_len);
 402 
 403         return skb;
 404 }
 405 
 406 static void nsim_dev_trap_report(struct nsim_dev_port *nsim_dev_port)
 407 {
 408         struct nsim_dev *nsim_dev = nsim_dev_port->ns->nsim_dev;
 409         struct devlink *devlink = priv_to_devlink(nsim_dev);
 410         struct nsim_trap_data *nsim_trap_data;
 411         int i;
 412 
 413         nsim_trap_data = nsim_dev->trap_data;
 414 
 415         spin_lock(&nsim_trap_data->trap_lock);
 416         for (i = 0; i < ARRAY_SIZE(nsim_traps_arr); i++) {
 417                 struct nsim_trap_item *nsim_trap_item;
 418                 struct sk_buff *skb;
 419 
 420                 nsim_trap_item = &nsim_trap_data->trap_items_arr[i];
 421                 if (nsim_trap_item->action == DEVLINK_TRAP_ACTION_DROP)
 422                         continue;
 423 
 424                 skb = nsim_dev_trap_skb_build();
 425                 if (!skb)
 426                         continue;
 427                 skb->dev = nsim_dev_port->ns->netdev;
 428 
 429                 /* Trapped packets are usually passed to devlink in softIRQ,
 430                  * but in this case they are generated in a workqueue. Disable
 431                  * softIRQs to prevent lockdep from complaining about
 432                  * "incosistent lock state".
 433                  */
 434                 local_bh_disable();
 435                 devlink_trap_report(devlink, skb, nsim_trap_item->trap_ctx,
 436                                     &nsim_dev_port->devlink_port);
 437                 local_bh_enable();
 438                 consume_skb(skb);
 439         }
 440         spin_unlock(&nsim_trap_data->trap_lock);
 441 }
 442 
 443 #define NSIM_TRAP_REPORT_INTERVAL_MS    100
 444 
 445 static void nsim_dev_trap_report_work(struct work_struct *work)
 446 {
 447         struct nsim_trap_data *nsim_trap_data;
 448         struct nsim_dev_port *nsim_dev_port;
 449         struct nsim_dev *nsim_dev;
 450 
 451         nsim_trap_data = container_of(work, struct nsim_trap_data,
 452                                       trap_report_dw.work);
 453         nsim_dev = nsim_trap_data->nsim_dev;
 454 
 455         /* For each running port and enabled packet trap, generate a UDP
 456          * packet with a random 5-tuple and report it.
 457          */
 458         mutex_lock(&nsim_dev->port_list_lock);
 459         list_for_each_entry(nsim_dev_port, &nsim_dev->port_list, list) {
 460                 if (!netif_running(nsim_dev_port->ns->netdev))
 461                         continue;
 462 
 463                 nsim_dev_trap_report(nsim_dev_port);
 464         }
 465         mutex_unlock(&nsim_dev->port_list_lock);
 466 
 467         schedule_delayed_work(&nsim_dev->trap_data->trap_report_dw,
 468                               msecs_to_jiffies(NSIM_TRAP_REPORT_INTERVAL_MS));
 469 }
 470 
 471 static int nsim_dev_traps_init(struct devlink *devlink)
 472 {
 473         struct nsim_dev *nsim_dev = devlink_priv(devlink);
 474         struct nsim_trap_data *nsim_trap_data;
 475         int err;
 476 
 477         nsim_trap_data = kzalloc(sizeof(*nsim_trap_data), GFP_KERNEL);
 478         if (!nsim_trap_data)
 479                 return -ENOMEM;
 480 
 481         nsim_trap_data->trap_items_arr = kcalloc(ARRAY_SIZE(nsim_traps_arr),
 482                                                  sizeof(struct nsim_trap_item),
 483                                                  GFP_KERNEL);
 484         if (!nsim_trap_data->trap_items_arr) {
 485                 err = -ENOMEM;
 486                 goto err_trap_data_free;
 487         }
 488 
 489         /* The lock is used to protect the action state of the registered
 490          * traps. The value is written by user and read in delayed work when
 491          * iterating over all the traps.
 492          */
 493         spin_lock_init(&nsim_trap_data->trap_lock);
 494         nsim_trap_data->nsim_dev = nsim_dev;
 495         nsim_dev->trap_data = nsim_trap_data;
 496 
 497         err = devlink_traps_register(devlink, nsim_traps_arr,
 498                                      ARRAY_SIZE(nsim_traps_arr), NULL);
 499         if (err)
 500                 goto err_trap_items_free;
 501 
 502         INIT_DELAYED_WORK(&nsim_dev->trap_data->trap_report_dw,
 503                           nsim_dev_trap_report_work);
 504         schedule_delayed_work(&nsim_dev->trap_data->trap_report_dw,
 505                               msecs_to_jiffies(NSIM_TRAP_REPORT_INTERVAL_MS));
 506 
 507         return 0;
 508 
 509 err_trap_items_free:
 510         kfree(nsim_trap_data->trap_items_arr);
 511 err_trap_data_free:
 512         kfree(nsim_trap_data);
 513         return err;
 514 }
 515 
 516 static void nsim_dev_traps_exit(struct devlink *devlink)
 517 {
 518         struct nsim_dev *nsim_dev = devlink_priv(devlink);
 519 
 520         cancel_delayed_work_sync(&nsim_dev->trap_data->trap_report_dw);
 521         devlink_traps_unregister(devlink, nsim_traps_arr,
 522                                  ARRAY_SIZE(nsim_traps_arr));
 523         kfree(nsim_dev->trap_data->trap_items_arr);
 524         kfree(nsim_dev->trap_data);
 525 }
 526 
 527 static int nsim_dev_reload_down(struct devlink *devlink,
 528                                 struct netlink_ext_ack *extack)
 529 {
 530         return 0;
 531 }
 532 
 533 static int nsim_dev_reload_up(struct devlink *devlink,
 534                               struct netlink_ext_ack *extack)
 535 {
 536         enum nsim_resource_id res_ids[] = {
 537                 NSIM_RESOURCE_IPV4_FIB, NSIM_RESOURCE_IPV4_FIB_RULES,
 538                 NSIM_RESOURCE_IPV6_FIB, NSIM_RESOURCE_IPV6_FIB_RULES
 539         };
 540         struct net *net = nsim_devlink_net(devlink);
 541         int i;
 542 
 543         for (i = 0; i < ARRAY_SIZE(res_ids); ++i) {
 544                 int err;
 545                 u64 val;
 546 
 547                 err = devlink_resource_size_get(devlink, res_ids[i], &val);
 548                 if (!err) {
 549                         err = nsim_fib_set_max(net, res_ids[i], val, extack);
 550                         if (err)
 551                                 return err;
 552                 }
 553         }
 554         nsim_devlink_param_load_driverinit_values(devlink);
 555 
 556         return 0;
 557 }
 558 
 559 #define NSIM_DEV_FLASH_SIZE 500000
 560 #define NSIM_DEV_FLASH_CHUNK_SIZE 1000
 561 #define NSIM_DEV_FLASH_CHUNK_TIME_MS 10
 562 
 563 static int nsim_dev_flash_update(struct devlink *devlink, const char *file_name,
 564                                  const char *component,
 565                                  struct netlink_ext_ack *extack)
 566 {
 567         struct nsim_dev *nsim_dev = devlink_priv(devlink);
 568         int i;
 569 
 570         if (nsim_dev->fw_update_status) {
 571                 devlink_flash_update_begin_notify(devlink);
 572                 devlink_flash_update_status_notify(devlink,
 573                                                    "Preparing to flash",
 574                                                    component, 0, 0);
 575         }
 576 
 577         for (i = 0; i < NSIM_DEV_FLASH_SIZE / NSIM_DEV_FLASH_CHUNK_SIZE; i++) {
 578                 if (nsim_dev->fw_update_status)
 579                         devlink_flash_update_status_notify(devlink, "Flashing",
 580                                                            component,
 581                                                            i * NSIM_DEV_FLASH_CHUNK_SIZE,
 582                                                            NSIM_DEV_FLASH_SIZE);
 583                 msleep(NSIM_DEV_FLASH_CHUNK_TIME_MS);
 584         }
 585 
 586         if (nsim_dev->fw_update_status) {
 587                 devlink_flash_update_status_notify(devlink, "Flashing",
 588                                                    component,
 589                                                    NSIM_DEV_FLASH_SIZE,
 590                                                    NSIM_DEV_FLASH_SIZE);
 591                 devlink_flash_update_status_notify(devlink, "Flashing done",
 592                                                    component, 0, 0);
 593                 devlink_flash_update_end_notify(devlink);
 594         }
 595 
 596         return 0;
 597 }
 598 
 599 static struct nsim_trap_item *
 600 nsim_dev_trap_item_lookup(struct nsim_dev *nsim_dev, u16 trap_id)
 601 {
 602         struct nsim_trap_data *nsim_trap_data = nsim_dev->trap_data;
 603         int i;
 604 
 605         for (i = 0; i < ARRAY_SIZE(nsim_traps_arr); i++) {
 606                 if (nsim_traps_arr[i].id == trap_id)
 607                         return &nsim_trap_data->trap_items_arr[i];
 608         }
 609 
 610         return NULL;
 611 }
 612 
 613 static int nsim_dev_devlink_trap_init(struct devlink *devlink,
 614                                       const struct devlink_trap *trap,
 615                                       void *trap_ctx)
 616 {
 617         struct nsim_dev *nsim_dev = devlink_priv(devlink);
 618         struct nsim_trap_item *nsim_trap_item;
 619 
 620         nsim_trap_item = nsim_dev_trap_item_lookup(nsim_dev, trap->id);
 621         if (WARN_ON(!nsim_trap_item))
 622                 return -ENOENT;
 623 
 624         nsim_trap_item->trap_ctx = trap_ctx;
 625         nsim_trap_item->action = trap->init_action;
 626 
 627         return 0;
 628 }
 629 
 630 static int
 631 nsim_dev_devlink_trap_action_set(struct devlink *devlink,
 632                                  const struct devlink_trap *trap,
 633                                  enum devlink_trap_action action)
 634 {
 635         struct nsim_dev *nsim_dev = devlink_priv(devlink);
 636         struct nsim_trap_item *nsim_trap_item;
 637 
 638         nsim_trap_item = nsim_dev_trap_item_lookup(nsim_dev, trap->id);
 639         if (WARN_ON(!nsim_trap_item))
 640                 return -ENOENT;
 641 
 642         spin_lock(&nsim_dev->trap_data->trap_lock);
 643         nsim_trap_item->action = action;
 644         spin_unlock(&nsim_dev->trap_data->trap_lock);
 645 
 646         return 0;
 647 }
 648 
 649 static const struct devlink_ops nsim_dev_devlink_ops = {
 650         .reload_down = nsim_dev_reload_down,
 651         .reload_up = nsim_dev_reload_up,
 652         .flash_update = nsim_dev_flash_update,
 653         .trap_init = nsim_dev_devlink_trap_init,
 654         .trap_action_set = nsim_dev_devlink_trap_action_set,
 655 };
 656 
 657 #define NSIM_DEV_MAX_MACS_DEFAULT 32
 658 #define NSIM_DEV_TEST1_DEFAULT true
 659 
 660 static struct nsim_dev *
 661 nsim_dev_create(struct nsim_bus_dev *nsim_bus_dev, unsigned int port_count)
 662 {
 663         struct nsim_dev *nsim_dev;
 664         struct devlink *devlink;
 665         int err;
 666 
 667         devlink = devlink_alloc(&nsim_dev_devlink_ops, sizeof(*nsim_dev));
 668         if (!devlink)
 669                 return ERR_PTR(-ENOMEM);
 670         nsim_dev = devlink_priv(devlink);
 671         nsim_dev->nsim_bus_dev = nsim_bus_dev;
 672         nsim_dev->switch_id.id_len = sizeof(nsim_dev->switch_id.id);
 673         get_random_bytes(nsim_dev->switch_id.id, nsim_dev->switch_id.id_len);
 674         INIT_LIST_HEAD(&nsim_dev->port_list);
 675         mutex_init(&nsim_dev->port_list_lock);
 676         nsim_dev->fw_update_status = true;
 677         nsim_dev->max_macs = NSIM_DEV_MAX_MACS_DEFAULT;
 678         nsim_dev->test1 = NSIM_DEV_TEST1_DEFAULT;
 679 
 680         err = nsim_dev_resources_register(devlink);
 681         if (err)
 682                 goto err_devlink_free;
 683 
 684         err = devlink_register(devlink, &nsim_bus_dev->dev);
 685         if (err)
 686                 goto err_resources_unregister;
 687 
 688         err = devlink_params_register(devlink, nsim_devlink_params,
 689                                       ARRAY_SIZE(nsim_devlink_params));
 690         if (err)
 691                 goto err_dl_unregister;
 692         nsim_devlink_set_params_init_values(nsim_dev, devlink);
 693 
 694         err = nsim_dev_dummy_region_init(nsim_dev, devlink);
 695         if (err)
 696                 goto err_params_unregister;
 697 
 698         err = nsim_dev_traps_init(devlink);
 699         if (err)
 700                 goto err_dummy_region_exit;
 701 
 702         err = nsim_dev_debugfs_init(nsim_dev);
 703         if (err)
 704                 goto err_traps_exit;
 705 
 706         err = nsim_bpf_dev_init(nsim_dev);
 707         if (err)
 708                 goto err_debugfs_exit;
 709 
 710         devlink_params_publish(devlink);
 711         devlink_reload_enable(devlink);
 712         return nsim_dev;
 713 
 714 err_debugfs_exit:
 715         nsim_dev_debugfs_exit(nsim_dev);
 716 err_traps_exit:
 717         nsim_dev_traps_exit(devlink);
 718 err_dummy_region_exit:
 719         nsim_dev_dummy_region_exit(nsim_dev);
 720 err_params_unregister:
 721         devlink_params_unregister(devlink, nsim_devlink_params,
 722                                   ARRAY_SIZE(nsim_devlink_params));
 723 err_dl_unregister:
 724         devlink_unregister(devlink);
 725 err_resources_unregister:
 726         devlink_resources_unregister(devlink, NULL);
 727 err_devlink_free:
 728         devlink_free(devlink);
 729         return ERR_PTR(err);
 730 }
 731 
 732 static void nsim_dev_destroy(struct nsim_dev *nsim_dev)
 733 {
 734         struct devlink *devlink = priv_to_devlink(nsim_dev);
 735 
 736         devlink_reload_disable(devlink);
 737         nsim_bpf_dev_exit(nsim_dev);
 738         nsim_dev_debugfs_exit(nsim_dev);
 739         nsim_dev_traps_exit(devlink);
 740         nsim_dev_dummy_region_exit(nsim_dev);
 741         devlink_params_unregister(devlink, nsim_devlink_params,
 742                                   ARRAY_SIZE(nsim_devlink_params));
 743         devlink_unregister(devlink);
 744         devlink_resources_unregister(devlink, NULL);
 745         mutex_destroy(&nsim_dev->port_list_lock);
 746         devlink_free(devlink);
 747 }
 748 
 749 static int __nsim_dev_port_add(struct nsim_dev *nsim_dev,
 750                                unsigned int port_index)
 751 {
 752         struct nsim_dev_port *nsim_dev_port;
 753         struct devlink_port *devlink_port;
 754         int err;
 755 
 756         nsim_dev_port = kzalloc(sizeof(*nsim_dev_port), GFP_KERNEL);
 757         if (!nsim_dev_port)
 758                 return -ENOMEM;
 759         nsim_dev_port->port_index = port_index;
 760 
 761         devlink_port = &nsim_dev_port->devlink_port;
 762         devlink_port_attrs_set(devlink_port, DEVLINK_PORT_FLAVOUR_PHYSICAL,
 763                                port_index + 1, 0, 0,
 764                                nsim_dev->switch_id.id,
 765                                nsim_dev->switch_id.id_len);
 766         err = devlink_port_register(priv_to_devlink(nsim_dev), devlink_port,
 767                                     port_index);
 768         if (err)
 769                 goto err_port_free;
 770 
 771         err = nsim_dev_port_debugfs_init(nsim_dev, nsim_dev_port);
 772         if (err)
 773                 goto err_dl_port_unregister;
 774 
 775         nsim_dev_port->ns = nsim_create(nsim_dev, nsim_dev_port);
 776         if (IS_ERR(nsim_dev_port->ns)) {
 777                 err = PTR_ERR(nsim_dev_port->ns);
 778                 goto err_port_debugfs_exit;
 779         }
 780 
 781         devlink_port_type_eth_set(devlink_port, nsim_dev_port->ns->netdev);
 782         list_add(&nsim_dev_port->list, &nsim_dev->port_list);
 783 
 784         return 0;
 785 
 786 err_port_debugfs_exit:
 787         nsim_dev_port_debugfs_exit(nsim_dev_port);
 788 err_dl_port_unregister:
 789         devlink_port_unregister(devlink_port);
 790 err_port_free:
 791         kfree(nsim_dev_port);
 792         return err;
 793 }
 794 
 795 static void __nsim_dev_port_del(struct nsim_dev_port *nsim_dev_port)
 796 {
 797         struct devlink_port *devlink_port = &nsim_dev_port->devlink_port;
 798 
 799         list_del(&nsim_dev_port->list);
 800         devlink_port_type_clear(devlink_port);
 801         nsim_destroy(nsim_dev_port->ns);
 802         nsim_dev_port_debugfs_exit(nsim_dev_port);
 803         devlink_port_unregister(devlink_port);
 804         kfree(nsim_dev_port);
 805 }
 806 
 807 static void nsim_dev_port_del_all(struct nsim_dev *nsim_dev)
 808 {
 809         struct nsim_dev_port *nsim_dev_port, *tmp;
 810 
 811         mutex_lock(&nsim_dev->port_list_lock);
 812         list_for_each_entry_safe(nsim_dev_port, tmp,
 813                                  &nsim_dev->port_list, list)
 814                 __nsim_dev_port_del(nsim_dev_port);
 815         mutex_unlock(&nsim_dev->port_list_lock);
 816 }
 817 
 818 int nsim_dev_probe(struct nsim_bus_dev *nsim_bus_dev)
 819 {
 820         struct nsim_dev *nsim_dev;
 821         int i;
 822         int err;
 823 
 824         nsim_dev = nsim_dev_create(nsim_bus_dev, nsim_bus_dev->port_count);
 825         if (IS_ERR(nsim_dev))
 826                 return PTR_ERR(nsim_dev);
 827         dev_set_drvdata(&nsim_bus_dev->dev, nsim_dev);
 828 
 829         mutex_lock(&nsim_dev->port_list_lock);
 830         for (i = 0; i < nsim_bus_dev->port_count; i++) {
 831                 err = __nsim_dev_port_add(nsim_dev, i);
 832                 if (err)
 833                         goto err_port_del_all;
 834         }
 835         mutex_unlock(&nsim_dev->port_list_lock);
 836         return 0;
 837 
 838 err_port_del_all:
 839         mutex_unlock(&nsim_dev->port_list_lock);
 840         nsim_dev_port_del_all(nsim_dev);
 841         nsim_dev_destroy(nsim_dev);
 842         return err;
 843 }
 844 
 845 void nsim_dev_remove(struct nsim_bus_dev *nsim_bus_dev)
 846 {
 847         struct nsim_dev *nsim_dev = dev_get_drvdata(&nsim_bus_dev->dev);
 848 
 849         nsim_dev_port_del_all(nsim_dev);
 850         nsim_dev_destroy(nsim_dev);
 851 }
 852 
 853 static struct nsim_dev_port *
 854 __nsim_dev_port_lookup(struct nsim_dev *nsim_dev, unsigned int port_index)
 855 {
 856         struct nsim_dev_port *nsim_dev_port;
 857 
 858         list_for_each_entry(nsim_dev_port, &nsim_dev->port_list, list)
 859                 if (nsim_dev_port->port_index == port_index)
 860                         return nsim_dev_port;
 861         return NULL;
 862 }
 863 
 864 int nsim_dev_port_add(struct nsim_bus_dev *nsim_bus_dev,
 865                       unsigned int port_index)
 866 {
 867         struct nsim_dev *nsim_dev = dev_get_drvdata(&nsim_bus_dev->dev);
 868         int err;
 869 
 870         mutex_lock(&nsim_dev->port_list_lock);
 871         if (__nsim_dev_port_lookup(nsim_dev, port_index))
 872                 err = -EEXIST;
 873         else
 874                 err = __nsim_dev_port_add(nsim_dev, port_index);
 875         mutex_unlock(&nsim_dev->port_list_lock);
 876         return err;
 877 }
 878 
 879 int nsim_dev_port_del(struct nsim_bus_dev *nsim_bus_dev,
 880                       unsigned int port_index)
 881 {
 882         struct nsim_dev *nsim_dev = dev_get_drvdata(&nsim_bus_dev->dev);
 883         struct nsim_dev_port *nsim_dev_port;
 884         int err = 0;
 885 
 886         mutex_lock(&nsim_dev->port_list_lock);
 887         nsim_dev_port = __nsim_dev_port_lookup(nsim_dev, port_index);
 888         if (!nsim_dev_port)
 889                 err = -ENOENT;
 890         else
 891                 __nsim_dev_port_del(nsim_dev_port);
 892         mutex_unlock(&nsim_dev->port_list_lock);
 893         return err;
 894 }
 895 
 896 int nsim_dev_init(void)
 897 {
 898         nsim_dev_ddir = debugfs_create_dir(DRV_NAME, NULL);
 899         if (IS_ERR_OR_NULL(nsim_dev_ddir))
 900                 return -ENOMEM;
 901         return 0;
 902 }
 903 
 904 void nsim_dev_exit(void)
 905 {
 906         debugfs_remove_recursive(nsim_dev_ddir);
 907 }

/* [<][>][^][v][top][bottom][index][help] */