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