xref: /linux/drivers/net/netdevsim/dev.c (revision 10a708c24a31ae1be1ea23d1c38da2691d1fd65c)
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/list.h>
21 #include <linux/mutex.h>
22 #include <linux/random.h>
23 #include <linux/rtnetlink.h>
24 #include <net/devlink.h>
25 
26 #include "netdevsim.h"
27 
28 static struct dentry *nsim_dev_ddir;
29 
30 static int nsim_dev_debugfs_init(struct nsim_dev *nsim_dev)
31 {
32 	char dev_ddir_name[16];
33 
34 	sprintf(dev_ddir_name, DRV_NAME "%u", nsim_dev->nsim_bus_dev->dev.id);
35 	nsim_dev->ddir = debugfs_create_dir(dev_ddir_name, nsim_dev_ddir);
36 	if (IS_ERR_OR_NULL(nsim_dev->ddir))
37 		return PTR_ERR_OR_ZERO(nsim_dev->ddir) ?: -EINVAL;
38 	nsim_dev->ports_ddir = debugfs_create_dir("ports", nsim_dev->ddir);
39 	if (IS_ERR_OR_NULL(nsim_dev->ports_ddir))
40 		return PTR_ERR_OR_ZERO(nsim_dev->ports_ddir) ?: -EINVAL;
41 	debugfs_create_bool("fw_update_status", 0600, nsim_dev->ddir,
42 			    &nsim_dev->fw_update_status);
43 	debugfs_create_u32("max_macs", 0600, nsim_dev->ddir,
44 			   &nsim_dev->max_macs);
45 	debugfs_create_bool("test1", 0600, nsim_dev->ddir,
46 			    &nsim_dev->test1);
47 	return 0;
48 }
49 
50 static void nsim_dev_debugfs_exit(struct nsim_dev *nsim_dev)
51 {
52 	debugfs_remove_recursive(nsim_dev->ports_ddir);
53 	debugfs_remove_recursive(nsim_dev->ddir);
54 }
55 
56 static int nsim_dev_port_debugfs_init(struct nsim_dev *nsim_dev,
57 				      struct nsim_dev_port *nsim_dev_port)
58 {
59 	char port_ddir_name[16];
60 	char dev_link_name[32];
61 
62 	sprintf(port_ddir_name, "%u", nsim_dev_port->port_index);
63 	nsim_dev_port->ddir = debugfs_create_dir(port_ddir_name,
64 						 nsim_dev->ports_ddir);
65 	if (IS_ERR_OR_NULL(nsim_dev_port->ddir))
66 		return -ENOMEM;
67 
68 	sprintf(dev_link_name, "../../../" DRV_NAME "%u",
69 		nsim_dev->nsim_bus_dev->dev.id);
70 	debugfs_create_symlink("dev", nsim_dev_port->ddir, dev_link_name);
71 
72 	return 0;
73 }
74 
75 static void nsim_dev_port_debugfs_exit(struct nsim_dev_port *nsim_dev_port)
76 {
77 	debugfs_remove_recursive(nsim_dev_port->ddir);
78 }
79 
80 static u64 nsim_dev_ipv4_fib_resource_occ_get(void *priv)
81 {
82 	struct nsim_dev *nsim_dev = priv;
83 
84 	return nsim_fib_get_val(nsim_dev->fib_data,
85 				NSIM_RESOURCE_IPV4_FIB, false);
86 }
87 
88 static u64 nsim_dev_ipv4_fib_rules_res_occ_get(void *priv)
89 {
90 	struct nsim_dev *nsim_dev = priv;
91 
92 	return nsim_fib_get_val(nsim_dev->fib_data,
93 				NSIM_RESOURCE_IPV4_FIB_RULES, false);
94 }
95 
96 static u64 nsim_dev_ipv6_fib_resource_occ_get(void *priv)
97 {
98 	struct nsim_dev *nsim_dev = priv;
99 
100 	return nsim_fib_get_val(nsim_dev->fib_data,
101 				NSIM_RESOURCE_IPV6_FIB, false);
102 }
103 
104 static u64 nsim_dev_ipv6_fib_rules_res_occ_get(void *priv)
105 {
106 	struct nsim_dev *nsim_dev = priv;
107 
108 	return nsim_fib_get_val(nsim_dev->fib_data,
109 				NSIM_RESOURCE_IPV6_FIB_RULES, false);
110 }
111 
112 static int nsim_dev_resources_register(struct devlink *devlink)
113 {
114 	struct nsim_dev *nsim_dev = devlink_priv(devlink);
115 	struct devlink_resource_size_params params = {
116 		.size_max = (u64)-1,
117 		.size_granularity = 1,
118 		.unit = DEVLINK_RESOURCE_UNIT_ENTRY
119 	};
120 	int err;
121 	u64 n;
122 
123 	/* Resources for IPv4 */
124 	err = devlink_resource_register(devlink, "IPv4", (u64)-1,
125 					NSIM_RESOURCE_IPV4,
126 					DEVLINK_RESOURCE_ID_PARENT_TOP,
127 					&params);
128 	if (err) {
129 		pr_err("Failed to register IPv4 top resource\n");
130 		goto out;
131 	}
132 
133 	n = nsim_fib_get_val(nsim_dev->fib_data,
134 			     NSIM_RESOURCE_IPV4_FIB, true);
135 	err = devlink_resource_register(devlink, "fib", n,
136 					NSIM_RESOURCE_IPV4_FIB,
137 					NSIM_RESOURCE_IPV4, &params);
138 	if (err) {
139 		pr_err("Failed to register IPv4 FIB resource\n");
140 		return err;
141 	}
142 
143 	n = nsim_fib_get_val(nsim_dev->fib_data,
144 			     NSIM_RESOURCE_IPV4_FIB_RULES, true);
145 	err = devlink_resource_register(devlink, "fib-rules", n,
146 					NSIM_RESOURCE_IPV4_FIB_RULES,
147 					NSIM_RESOURCE_IPV4, &params);
148 	if (err) {
149 		pr_err("Failed to register IPv4 FIB rules resource\n");
150 		return err;
151 	}
152 
153 	/* Resources for IPv6 */
154 	err = devlink_resource_register(devlink, "IPv6", (u64)-1,
155 					NSIM_RESOURCE_IPV6,
156 					DEVLINK_RESOURCE_ID_PARENT_TOP,
157 					&params);
158 	if (err) {
159 		pr_err("Failed to register IPv6 top resource\n");
160 		goto out;
161 	}
162 
163 	n = nsim_fib_get_val(nsim_dev->fib_data,
164 			     NSIM_RESOURCE_IPV6_FIB, true);
165 	err = devlink_resource_register(devlink, "fib", n,
166 					NSIM_RESOURCE_IPV6_FIB,
167 					NSIM_RESOURCE_IPV6, &params);
168 	if (err) {
169 		pr_err("Failed to register IPv6 FIB resource\n");
170 		return err;
171 	}
172 
173 	n = nsim_fib_get_val(nsim_dev->fib_data,
174 			     NSIM_RESOURCE_IPV6_FIB_RULES, true);
175 	err = devlink_resource_register(devlink, "fib-rules", n,
176 					NSIM_RESOURCE_IPV6_FIB_RULES,
177 					NSIM_RESOURCE_IPV6, &params);
178 	if (err) {
179 		pr_err("Failed to register IPv6 FIB rules resource\n");
180 		return err;
181 	}
182 
183 	devlink_resource_occ_get_register(devlink,
184 					  NSIM_RESOURCE_IPV4_FIB,
185 					  nsim_dev_ipv4_fib_resource_occ_get,
186 					  nsim_dev);
187 	devlink_resource_occ_get_register(devlink,
188 					  NSIM_RESOURCE_IPV4_FIB_RULES,
189 					  nsim_dev_ipv4_fib_rules_res_occ_get,
190 					  nsim_dev);
191 	devlink_resource_occ_get_register(devlink,
192 					  NSIM_RESOURCE_IPV6_FIB,
193 					  nsim_dev_ipv6_fib_resource_occ_get,
194 					  nsim_dev);
195 	devlink_resource_occ_get_register(devlink,
196 					  NSIM_RESOURCE_IPV6_FIB_RULES,
197 					  nsim_dev_ipv6_fib_rules_res_occ_get,
198 					  nsim_dev);
199 out:
200 	return err;
201 }
202 
203 enum nsim_devlink_param_id {
204 	NSIM_DEVLINK_PARAM_ID_BASE = DEVLINK_PARAM_GENERIC_ID_MAX,
205 	NSIM_DEVLINK_PARAM_ID_TEST1,
206 };
207 
208 static const struct devlink_param nsim_devlink_params[] = {
209 	DEVLINK_PARAM_GENERIC(MAX_MACS,
210 			      BIT(DEVLINK_PARAM_CMODE_DRIVERINIT),
211 			      NULL, NULL, NULL),
212 	DEVLINK_PARAM_DRIVER(NSIM_DEVLINK_PARAM_ID_TEST1,
213 			     "test1", DEVLINK_PARAM_TYPE_BOOL,
214 			     BIT(DEVLINK_PARAM_CMODE_DRIVERINIT),
215 			     NULL, NULL, NULL),
216 };
217 
218 static void nsim_devlink_set_params_init_values(struct nsim_dev *nsim_dev,
219 						struct devlink *devlink)
220 {
221 	union devlink_param_value value;
222 
223 	value.vu32 = nsim_dev->max_macs;
224 	devlink_param_driverinit_value_set(devlink,
225 					   DEVLINK_PARAM_GENERIC_ID_MAX_MACS,
226 					   value);
227 	value.vbool = nsim_dev->test1;
228 	devlink_param_driverinit_value_set(devlink,
229 					   NSIM_DEVLINK_PARAM_ID_TEST1,
230 					   value);
231 }
232 
233 static void nsim_devlink_param_load_driverinit_values(struct devlink *devlink)
234 {
235 	struct nsim_dev *nsim_dev = devlink_priv(devlink);
236 	union devlink_param_value saved_value;
237 	int err;
238 
239 	err = devlink_param_driverinit_value_get(devlink,
240 						 DEVLINK_PARAM_GENERIC_ID_MAX_MACS,
241 						 &saved_value);
242 	if (!err)
243 		nsim_dev->max_macs = saved_value.vu32;
244 	err = devlink_param_driverinit_value_get(devlink,
245 						 NSIM_DEVLINK_PARAM_ID_TEST1,
246 						 &saved_value);
247 	if (!err)
248 		nsim_dev->test1 = saved_value.vbool;
249 }
250 
251 static int nsim_dev_reload(struct devlink *devlink,
252 			   struct netlink_ext_ack *extack)
253 {
254 	struct nsim_dev *nsim_dev = devlink_priv(devlink);
255 	enum nsim_resource_id res_ids[] = {
256 		NSIM_RESOURCE_IPV4_FIB, NSIM_RESOURCE_IPV4_FIB_RULES,
257 		NSIM_RESOURCE_IPV6_FIB, NSIM_RESOURCE_IPV6_FIB_RULES
258 	};
259 	int i;
260 
261 	for (i = 0; i < ARRAY_SIZE(res_ids); ++i) {
262 		int err;
263 		u64 val;
264 
265 		err = devlink_resource_size_get(devlink, res_ids[i], &val);
266 		if (!err) {
267 			err = nsim_fib_set_max(nsim_dev->fib_data,
268 					       res_ids[i], val, extack);
269 			if (err)
270 				return err;
271 		}
272 	}
273 	nsim_devlink_param_load_driverinit_values(devlink);
274 
275 	return 0;
276 }
277 
278 #define NSIM_DEV_FLASH_SIZE 500000
279 #define NSIM_DEV_FLASH_CHUNK_SIZE 1000
280 #define NSIM_DEV_FLASH_CHUNK_TIME_MS 10
281 
282 static int nsim_dev_flash_update(struct devlink *devlink, const char *file_name,
283 				 const char *component,
284 				 struct netlink_ext_ack *extack)
285 {
286 	struct nsim_dev *nsim_dev = devlink_priv(devlink);
287 	int i;
288 
289 	if (nsim_dev->fw_update_status) {
290 		devlink_flash_update_begin_notify(devlink);
291 		devlink_flash_update_status_notify(devlink,
292 						   "Preparing to flash",
293 						   component, 0, 0);
294 	}
295 
296 	for (i = 0; i < NSIM_DEV_FLASH_SIZE / NSIM_DEV_FLASH_CHUNK_SIZE; i++) {
297 		if (nsim_dev->fw_update_status)
298 			devlink_flash_update_status_notify(devlink, "Flashing",
299 							   component,
300 							   i * NSIM_DEV_FLASH_CHUNK_SIZE,
301 							   NSIM_DEV_FLASH_SIZE);
302 		msleep(NSIM_DEV_FLASH_CHUNK_TIME_MS);
303 	}
304 
305 	if (nsim_dev->fw_update_status) {
306 		devlink_flash_update_status_notify(devlink, "Flashing",
307 						   component,
308 						   NSIM_DEV_FLASH_SIZE,
309 						   NSIM_DEV_FLASH_SIZE);
310 		devlink_flash_update_status_notify(devlink, "Flashing done",
311 						   component, 0, 0);
312 		devlink_flash_update_end_notify(devlink);
313 	}
314 
315 	return 0;
316 }
317 
318 static const struct devlink_ops nsim_dev_devlink_ops = {
319 	.reload = nsim_dev_reload,
320 	.flash_update = nsim_dev_flash_update,
321 };
322 
323 #define NSIM_DEV_MAX_MACS_DEFAULT 32
324 #define NSIM_DEV_TEST1_DEFAULT true
325 
326 static struct nsim_dev *
327 nsim_dev_create(struct nsim_bus_dev *nsim_bus_dev, unsigned int port_count)
328 {
329 	struct nsim_dev *nsim_dev;
330 	struct devlink *devlink;
331 	int err;
332 
333 	devlink = devlink_alloc(&nsim_dev_devlink_ops, sizeof(*nsim_dev));
334 	if (!devlink)
335 		return ERR_PTR(-ENOMEM);
336 	nsim_dev = devlink_priv(devlink);
337 	nsim_dev->nsim_bus_dev = nsim_bus_dev;
338 	nsim_dev->switch_id.id_len = sizeof(nsim_dev->switch_id.id);
339 	get_random_bytes(nsim_dev->switch_id.id, nsim_dev->switch_id.id_len);
340 	INIT_LIST_HEAD(&nsim_dev->port_list);
341 	mutex_init(&nsim_dev->port_list_lock);
342 	nsim_dev->fw_update_status = true;
343 	nsim_dev->max_macs = NSIM_DEV_MAX_MACS_DEFAULT;
344 	nsim_dev->test1 = NSIM_DEV_TEST1_DEFAULT;
345 
346 	nsim_dev->fib_data = nsim_fib_create();
347 	if (IS_ERR(nsim_dev->fib_data)) {
348 		err = PTR_ERR(nsim_dev->fib_data);
349 		goto err_devlink_free;
350 	}
351 
352 	err = nsim_dev_resources_register(devlink);
353 	if (err)
354 		goto err_fib_destroy;
355 
356 	err = devlink_register(devlink, &nsim_bus_dev->dev);
357 	if (err)
358 		goto err_resources_unregister;
359 
360 	err = devlink_params_register(devlink, nsim_devlink_params,
361 				      ARRAY_SIZE(nsim_devlink_params));
362 	if (err)
363 		goto err_dl_unregister;
364 	nsim_devlink_set_params_init_values(nsim_dev, devlink);
365 
366 	err = nsim_dev_debugfs_init(nsim_dev);
367 	if (err)
368 		goto err_params_unregister;
369 
370 	err = nsim_bpf_dev_init(nsim_dev);
371 	if (err)
372 		goto err_debugfs_exit;
373 
374 	devlink_params_publish(devlink);
375 	return nsim_dev;
376 
377 err_debugfs_exit:
378 	nsim_dev_debugfs_exit(nsim_dev);
379 err_params_unregister:
380 	devlink_params_unregister(devlink, nsim_devlink_params,
381 				  ARRAY_SIZE(nsim_devlink_params));
382 err_dl_unregister:
383 	devlink_unregister(devlink);
384 err_resources_unregister:
385 	devlink_resources_unregister(devlink, NULL);
386 err_fib_destroy:
387 	nsim_fib_destroy(nsim_dev->fib_data);
388 err_devlink_free:
389 	devlink_free(devlink);
390 	return ERR_PTR(err);
391 }
392 
393 static void nsim_dev_destroy(struct nsim_dev *nsim_dev)
394 {
395 	struct devlink *devlink = priv_to_devlink(nsim_dev);
396 
397 	nsim_bpf_dev_exit(nsim_dev);
398 	nsim_dev_debugfs_exit(nsim_dev);
399 	devlink_params_unregister(devlink, nsim_devlink_params,
400 				  ARRAY_SIZE(nsim_devlink_params));
401 	devlink_unregister(devlink);
402 	devlink_resources_unregister(devlink, NULL);
403 	nsim_fib_destroy(nsim_dev->fib_data);
404 	mutex_destroy(&nsim_dev->port_list_lock);
405 	devlink_free(devlink);
406 }
407 
408 static int __nsim_dev_port_add(struct nsim_dev *nsim_dev,
409 			       unsigned int port_index)
410 {
411 	struct nsim_dev_port *nsim_dev_port;
412 	struct devlink_port *devlink_port;
413 	int err;
414 
415 	nsim_dev_port = kzalloc(sizeof(*nsim_dev_port), GFP_KERNEL);
416 	if (!nsim_dev_port)
417 		return -ENOMEM;
418 	nsim_dev_port->port_index = port_index;
419 
420 	devlink_port = &nsim_dev_port->devlink_port;
421 	devlink_port_attrs_set(devlink_port, DEVLINK_PORT_FLAVOUR_PHYSICAL,
422 			       port_index + 1, 0, 0,
423 			       nsim_dev->switch_id.id,
424 			       nsim_dev->switch_id.id_len);
425 	err = devlink_port_register(priv_to_devlink(nsim_dev), devlink_port,
426 				    port_index);
427 	if (err)
428 		goto err_port_free;
429 
430 	err = nsim_dev_port_debugfs_init(nsim_dev, nsim_dev_port);
431 	if (err)
432 		goto err_dl_port_unregister;
433 
434 	nsim_dev_port->ns = nsim_create(nsim_dev, nsim_dev_port);
435 	if (IS_ERR(nsim_dev_port->ns)) {
436 		err = PTR_ERR(nsim_dev_port->ns);
437 		goto err_port_debugfs_exit;
438 	}
439 
440 	devlink_port_type_eth_set(devlink_port, nsim_dev_port->ns->netdev);
441 	list_add(&nsim_dev_port->list, &nsim_dev->port_list);
442 
443 	return 0;
444 
445 err_port_debugfs_exit:
446 	nsim_dev_port_debugfs_exit(nsim_dev_port);
447 err_dl_port_unregister:
448 	devlink_port_unregister(devlink_port);
449 err_port_free:
450 	kfree(nsim_dev_port);
451 	return err;
452 }
453 
454 static void __nsim_dev_port_del(struct nsim_dev_port *nsim_dev_port)
455 {
456 	struct devlink_port *devlink_port = &nsim_dev_port->devlink_port;
457 
458 	list_del(&nsim_dev_port->list);
459 	devlink_port_type_clear(devlink_port);
460 	nsim_destroy(nsim_dev_port->ns);
461 	nsim_dev_port_debugfs_exit(nsim_dev_port);
462 	devlink_port_unregister(devlink_port);
463 	kfree(nsim_dev_port);
464 }
465 
466 static void nsim_dev_port_del_all(struct nsim_dev *nsim_dev)
467 {
468 	struct nsim_dev_port *nsim_dev_port, *tmp;
469 
470 	list_for_each_entry_safe(nsim_dev_port, tmp,
471 				 &nsim_dev->port_list, list)
472 		__nsim_dev_port_del(nsim_dev_port);
473 }
474 
475 int nsim_dev_probe(struct nsim_bus_dev *nsim_bus_dev)
476 {
477 	struct nsim_dev *nsim_dev;
478 	int i;
479 	int err;
480 
481 	nsim_dev = nsim_dev_create(nsim_bus_dev, nsim_bus_dev->port_count);
482 	if (IS_ERR(nsim_dev))
483 		return PTR_ERR(nsim_dev);
484 	dev_set_drvdata(&nsim_bus_dev->dev, nsim_dev);
485 
486 	for (i = 0; i < nsim_bus_dev->port_count; i++) {
487 		err = __nsim_dev_port_add(nsim_dev, i);
488 		if (err)
489 			goto err_port_del_all;
490 	}
491 	return 0;
492 
493 err_port_del_all:
494 	nsim_dev_port_del_all(nsim_dev);
495 	nsim_dev_destroy(nsim_dev);
496 	return err;
497 }
498 
499 void nsim_dev_remove(struct nsim_bus_dev *nsim_bus_dev)
500 {
501 	struct nsim_dev *nsim_dev = dev_get_drvdata(&nsim_bus_dev->dev);
502 
503 	nsim_dev_port_del_all(nsim_dev);
504 	nsim_dev_destroy(nsim_dev);
505 }
506 
507 static struct nsim_dev_port *
508 __nsim_dev_port_lookup(struct nsim_dev *nsim_dev, unsigned int port_index)
509 {
510 	struct nsim_dev_port *nsim_dev_port;
511 
512 	list_for_each_entry(nsim_dev_port, &nsim_dev->port_list, list)
513 		if (nsim_dev_port->port_index == port_index)
514 			return nsim_dev_port;
515 	return NULL;
516 }
517 
518 int nsim_dev_port_add(struct nsim_bus_dev *nsim_bus_dev,
519 		      unsigned int port_index)
520 {
521 	struct nsim_dev *nsim_dev = dev_get_drvdata(&nsim_bus_dev->dev);
522 	int err;
523 
524 	mutex_lock(&nsim_dev->port_list_lock);
525 	if (__nsim_dev_port_lookup(nsim_dev, port_index))
526 		err = -EEXIST;
527 	else
528 		err = __nsim_dev_port_add(nsim_dev, port_index);
529 	mutex_unlock(&nsim_dev->port_list_lock);
530 	return err;
531 }
532 
533 int nsim_dev_port_del(struct nsim_bus_dev *nsim_bus_dev,
534 		      unsigned int port_index)
535 {
536 	struct nsim_dev *nsim_dev = dev_get_drvdata(&nsim_bus_dev->dev);
537 	struct nsim_dev_port *nsim_dev_port;
538 	int err = 0;
539 
540 	mutex_lock(&nsim_dev->port_list_lock);
541 	nsim_dev_port = __nsim_dev_port_lookup(nsim_dev, port_index);
542 	if (!nsim_dev_port)
543 		err = -ENOENT;
544 	else
545 		__nsim_dev_port_del(nsim_dev_port);
546 	mutex_unlock(&nsim_dev->port_list_lock);
547 	return err;
548 }
549 
550 int nsim_dev_init(void)
551 {
552 	nsim_dev_ddir = debugfs_create_dir(DRV_NAME, NULL);
553 	if (IS_ERR_OR_NULL(nsim_dev_ddir))
554 		return -ENOMEM;
555 	return 0;
556 }
557 
558 void nsim_dev_exit(void)
559 {
560 	debugfs_remove_recursive(nsim_dev_ddir);
561 }
562