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