xref: /linux-6.15/drivers/net/netdevsim/dev.c (revision d514f41e)
18fb4bc6fSJiri Pirko /*
28fb4bc6fSJiri Pirko  * Copyright (c) 2018 Cumulus Networks. All rights reserved.
38fb4bc6fSJiri Pirko  * Copyright (c) 2018 David Ahern <[email protected]>
48fb4bc6fSJiri Pirko  * Copyright (c) 2019 Mellanox Technologies. All rights reserved.
58fb4bc6fSJiri Pirko  *
68fb4bc6fSJiri Pirko  * This software is licensed under the GNU General License Version 2,
78fb4bc6fSJiri Pirko  * June 1991 as shown in the file COPYING in the top-level directory of this
88fb4bc6fSJiri Pirko  * source tree.
98fb4bc6fSJiri Pirko  *
108fb4bc6fSJiri Pirko  * THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS"
118fb4bc6fSJiri Pirko  * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
128fb4bc6fSJiri Pirko  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
138fb4bc6fSJiri Pirko  * FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE
148fb4bc6fSJiri Pirko  * OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME
158fb4bc6fSJiri Pirko  * THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
168fb4bc6fSJiri Pirko  */
178fb4bc6fSJiri Pirko 
18*d514f41eSJiri Pirko #include <linux/debugfs.h>
198fb4bc6fSJiri Pirko #include <linux/device.h>
208fb4bc6fSJiri Pirko #include <linux/rtnetlink.h>
218fb4bc6fSJiri Pirko #include <net/devlink.h>
228fb4bc6fSJiri Pirko 
238fb4bc6fSJiri Pirko #include "netdevsim.h"
248fb4bc6fSJiri Pirko 
25*d514f41eSJiri Pirko static struct dentry *nsim_dev_ddir;
26*d514f41eSJiri Pirko 
27*d514f41eSJiri Pirko static int nsim_dev_debugfs_init(struct nsim_dev *nsim_dev)
28*d514f41eSJiri Pirko {
29*d514f41eSJiri Pirko 	char dev_ddir_name[10];
30*d514f41eSJiri Pirko 
31*d514f41eSJiri Pirko 	sprintf(dev_ddir_name, "%u", nsim_dev->nsim_bus_dev->dev.id);
32*d514f41eSJiri Pirko 	nsim_dev->ddir = debugfs_create_dir(dev_ddir_name, nsim_dev_ddir);
33*d514f41eSJiri Pirko 	if (IS_ERR_OR_NULL(nsim_dev->ddir))
34*d514f41eSJiri Pirko 		return PTR_ERR_OR_ZERO(nsim_dev->ddir) ?: -EINVAL;
35*d514f41eSJiri Pirko 	return 0;
36*d514f41eSJiri Pirko }
37*d514f41eSJiri Pirko 
38*d514f41eSJiri Pirko static void nsim_dev_debugfs_exit(struct nsim_dev *nsim_dev)
39*d514f41eSJiri Pirko {
40*d514f41eSJiri Pirko 	debugfs_remove_recursive(nsim_dev->ddir);
41*d514f41eSJiri Pirko }
42*d514f41eSJiri Pirko 
438fb4bc6fSJiri Pirko static u64 nsim_dev_ipv4_fib_resource_occ_get(void *priv)
448fb4bc6fSJiri Pirko {
458fb4bc6fSJiri Pirko 	struct nsim_dev *nsim_dev = priv;
468fb4bc6fSJiri Pirko 
478fb4bc6fSJiri Pirko 	return nsim_fib_get_val(nsim_dev->fib_data,
488fb4bc6fSJiri Pirko 				NSIM_RESOURCE_IPV4_FIB, false);
498fb4bc6fSJiri Pirko }
508fb4bc6fSJiri Pirko 
518fb4bc6fSJiri Pirko static u64 nsim_dev_ipv4_fib_rules_res_occ_get(void *priv)
528fb4bc6fSJiri Pirko {
538fb4bc6fSJiri Pirko 	struct nsim_dev *nsim_dev = priv;
548fb4bc6fSJiri Pirko 
558fb4bc6fSJiri Pirko 	return nsim_fib_get_val(nsim_dev->fib_data,
568fb4bc6fSJiri Pirko 				NSIM_RESOURCE_IPV4_FIB_RULES, false);
578fb4bc6fSJiri Pirko }
588fb4bc6fSJiri Pirko 
598fb4bc6fSJiri Pirko static u64 nsim_dev_ipv6_fib_resource_occ_get(void *priv)
608fb4bc6fSJiri Pirko {
618fb4bc6fSJiri Pirko 	struct nsim_dev *nsim_dev = priv;
628fb4bc6fSJiri Pirko 
638fb4bc6fSJiri Pirko 	return nsim_fib_get_val(nsim_dev->fib_data,
648fb4bc6fSJiri Pirko 				NSIM_RESOURCE_IPV6_FIB, false);
658fb4bc6fSJiri Pirko }
668fb4bc6fSJiri Pirko 
678fb4bc6fSJiri Pirko static u64 nsim_dev_ipv6_fib_rules_res_occ_get(void *priv)
688fb4bc6fSJiri Pirko {
698fb4bc6fSJiri Pirko 	struct nsim_dev *nsim_dev = priv;
708fb4bc6fSJiri Pirko 
718fb4bc6fSJiri Pirko 	return nsim_fib_get_val(nsim_dev->fib_data,
728fb4bc6fSJiri Pirko 				NSIM_RESOURCE_IPV6_FIB_RULES, false);
738fb4bc6fSJiri Pirko }
748fb4bc6fSJiri Pirko 
758fb4bc6fSJiri Pirko static int nsim_dev_resources_register(struct devlink *devlink)
768fb4bc6fSJiri Pirko {
778fb4bc6fSJiri Pirko 	struct nsim_dev *nsim_dev = devlink_priv(devlink);
788fb4bc6fSJiri Pirko 	struct devlink_resource_size_params params = {
798fb4bc6fSJiri Pirko 		.size_max = (u64)-1,
808fb4bc6fSJiri Pirko 		.size_granularity = 1,
818fb4bc6fSJiri Pirko 		.unit = DEVLINK_RESOURCE_UNIT_ENTRY
828fb4bc6fSJiri Pirko 	};
838fb4bc6fSJiri Pirko 	int err;
848fb4bc6fSJiri Pirko 	u64 n;
858fb4bc6fSJiri Pirko 
868fb4bc6fSJiri Pirko 	/* Resources for IPv4 */
878fb4bc6fSJiri Pirko 	err = devlink_resource_register(devlink, "IPv4", (u64)-1,
888fb4bc6fSJiri Pirko 					NSIM_RESOURCE_IPV4,
898fb4bc6fSJiri Pirko 					DEVLINK_RESOURCE_ID_PARENT_TOP,
908fb4bc6fSJiri Pirko 					&params);
918fb4bc6fSJiri Pirko 	if (err) {
928fb4bc6fSJiri Pirko 		pr_err("Failed to register IPv4 top resource\n");
938fb4bc6fSJiri Pirko 		goto out;
948fb4bc6fSJiri Pirko 	}
958fb4bc6fSJiri Pirko 
968fb4bc6fSJiri Pirko 	n = nsim_fib_get_val(nsim_dev->fib_data,
978fb4bc6fSJiri Pirko 			     NSIM_RESOURCE_IPV4_FIB, true);
988fb4bc6fSJiri Pirko 	err = devlink_resource_register(devlink, "fib", n,
998fb4bc6fSJiri Pirko 					NSIM_RESOURCE_IPV4_FIB,
1008fb4bc6fSJiri Pirko 					NSIM_RESOURCE_IPV4, &params);
1018fb4bc6fSJiri Pirko 	if (err) {
1028fb4bc6fSJiri Pirko 		pr_err("Failed to register IPv4 FIB resource\n");
1038fb4bc6fSJiri Pirko 		return err;
1048fb4bc6fSJiri Pirko 	}
1058fb4bc6fSJiri Pirko 
1068fb4bc6fSJiri Pirko 	n = nsim_fib_get_val(nsim_dev->fib_data,
1078fb4bc6fSJiri Pirko 			     NSIM_RESOURCE_IPV4_FIB_RULES, true);
1088fb4bc6fSJiri Pirko 	err = devlink_resource_register(devlink, "fib-rules", n,
1098fb4bc6fSJiri Pirko 					NSIM_RESOURCE_IPV4_FIB_RULES,
1108fb4bc6fSJiri Pirko 					NSIM_RESOURCE_IPV4, &params);
1118fb4bc6fSJiri Pirko 	if (err) {
1128fb4bc6fSJiri Pirko 		pr_err("Failed to register IPv4 FIB rules resource\n");
1138fb4bc6fSJiri Pirko 		return err;
1148fb4bc6fSJiri Pirko 	}
1158fb4bc6fSJiri Pirko 
1168fb4bc6fSJiri Pirko 	/* Resources for IPv6 */
1178fb4bc6fSJiri Pirko 	err = devlink_resource_register(devlink, "IPv6", (u64)-1,
1188fb4bc6fSJiri Pirko 					NSIM_RESOURCE_IPV6,
1198fb4bc6fSJiri Pirko 					DEVLINK_RESOURCE_ID_PARENT_TOP,
1208fb4bc6fSJiri Pirko 					&params);
1218fb4bc6fSJiri Pirko 	if (err) {
1228fb4bc6fSJiri Pirko 		pr_err("Failed to register IPv6 top resource\n");
1238fb4bc6fSJiri Pirko 		goto out;
1248fb4bc6fSJiri Pirko 	}
1258fb4bc6fSJiri Pirko 
1268fb4bc6fSJiri Pirko 	n = nsim_fib_get_val(nsim_dev->fib_data,
1278fb4bc6fSJiri Pirko 			     NSIM_RESOURCE_IPV6_FIB, true);
1288fb4bc6fSJiri Pirko 	err = devlink_resource_register(devlink, "fib", n,
1298fb4bc6fSJiri Pirko 					NSIM_RESOURCE_IPV6_FIB,
1308fb4bc6fSJiri Pirko 					NSIM_RESOURCE_IPV6, &params);
1318fb4bc6fSJiri Pirko 	if (err) {
1328fb4bc6fSJiri Pirko 		pr_err("Failed to register IPv6 FIB resource\n");
1338fb4bc6fSJiri Pirko 		return err;
1348fb4bc6fSJiri Pirko 	}
1358fb4bc6fSJiri Pirko 
1368fb4bc6fSJiri Pirko 	n = nsim_fib_get_val(nsim_dev->fib_data,
1378fb4bc6fSJiri Pirko 			     NSIM_RESOURCE_IPV6_FIB_RULES, true);
1388fb4bc6fSJiri Pirko 	err = devlink_resource_register(devlink, "fib-rules", n,
1398fb4bc6fSJiri Pirko 					NSIM_RESOURCE_IPV6_FIB_RULES,
1408fb4bc6fSJiri Pirko 					NSIM_RESOURCE_IPV6, &params);
1418fb4bc6fSJiri Pirko 	if (err) {
1428fb4bc6fSJiri Pirko 		pr_err("Failed to register IPv6 FIB rules resource\n");
1438fb4bc6fSJiri Pirko 		return err;
1448fb4bc6fSJiri Pirko 	}
1458fb4bc6fSJiri Pirko 
1468fb4bc6fSJiri Pirko 	devlink_resource_occ_get_register(devlink,
1478fb4bc6fSJiri Pirko 					  NSIM_RESOURCE_IPV4_FIB,
1488fb4bc6fSJiri Pirko 					  nsim_dev_ipv4_fib_resource_occ_get,
1498fb4bc6fSJiri Pirko 					  nsim_dev);
1508fb4bc6fSJiri Pirko 	devlink_resource_occ_get_register(devlink,
1518fb4bc6fSJiri Pirko 					  NSIM_RESOURCE_IPV4_FIB_RULES,
1528fb4bc6fSJiri Pirko 					  nsim_dev_ipv4_fib_rules_res_occ_get,
1538fb4bc6fSJiri Pirko 					  nsim_dev);
1548fb4bc6fSJiri Pirko 	devlink_resource_occ_get_register(devlink,
1558fb4bc6fSJiri Pirko 					  NSIM_RESOURCE_IPV6_FIB,
1568fb4bc6fSJiri Pirko 					  nsim_dev_ipv6_fib_resource_occ_get,
1578fb4bc6fSJiri Pirko 					  nsim_dev);
1588fb4bc6fSJiri Pirko 	devlink_resource_occ_get_register(devlink,
1598fb4bc6fSJiri Pirko 					  NSIM_RESOURCE_IPV6_FIB_RULES,
1608fb4bc6fSJiri Pirko 					  nsim_dev_ipv6_fib_rules_res_occ_get,
1618fb4bc6fSJiri Pirko 					  nsim_dev);
1628fb4bc6fSJiri Pirko out:
1638fb4bc6fSJiri Pirko 	return err;
1648fb4bc6fSJiri Pirko }
1658fb4bc6fSJiri Pirko 
1668fb4bc6fSJiri Pirko static int nsim_dev_reload(struct devlink *devlink,
1678fb4bc6fSJiri Pirko 			   struct netlink_ext_ack *extack)
1688fb4bc6fSJiri Pirko {
1698fb4bc6fSJiri Pirko 	struct nsim_dev *nsim_dev = devlink_priv(devlink);
1708fb4bc6fSJiri Pirko 	enum nsim_resource_id res_ids[] = {
1718fb4bc6fSJiri Pirko 		NSIM_RESOURCE_IPV4_FIB, NSIM_RESOURCE_IPV4_FIB_RULES,
1728fb4bc6fSJiri Pirko 		NSIM_RESOURCE_IPV6_FIB, NSIM_RESOURCE_IPV6_FIB_RULES
1738fb4bc6fSJiri Pirko 	};
1748fb4bc6fSJiri Pirko 	int i;
1758fb4bc6fSJiri Pirko 
1768fb4bc6fSJiri Pirko 	for (i = 0; i < ARRAY_SIZE(res_ids); ++i) {
1778fb4bc6fSJiri Pirko 		int err;
1788fb4bc6fSJiri Pirko 		u64 val;
1798fb4bc6fSJiri Pirko 
1808fb4bc6fSJiri Pirko 		err = devlink_resource_size_get(devlink, res_ids[i], &val);
1818fb4bc6fSJiri Pirko 		if (!err) {
1828fb4bc6fSJiri Pirko 			err = nsim_fib_set_max(nsim_dev->fib_data,
1838fb4bc6fSJiri Pirko 					       res_ids[i], val, extack);
1848fb4bc6fSJiri Pirko 			if (err)
1858fb4bc6fSJiri Pirko 				return err;
1868fb4bc6fSJiri Pirko 		}
1878fb4bc6fSJiri Pirko 	}
1888fb4bc6fSJiri Pirko 
1898fb4bc6fSJiri Pirko 	return 0;
1908fb4bc6fSJiri Pirko }
1918fb4bc6fSJiri Pirko 
1928fb4bc6fSJiri Pirko static const struct devlink_ops nsim_dev_devlink_ops = {
1938fb4bc6fSJiri Pirko 	.reload = nsim_dev_reload,
1948fb4bc6fSJiri Pirko };
1958fb4bc6fSJiri Pirko 
196a60f9e48SJiri Pirko static struct nsim_dev *nsim_dev_create(struct nsim_bus_dev *nsim_bus_dev)
1978fb4bc6fSJiri Pirko {
1988fb4bc6fSJiri Pirko 	struct nsim_dev *nsim_dev;
1998fb4bc6fSJiri Pirko 	struct devlink *devlink;
2008fb4bc6fSJiri Pirko 	int err;
2018fb4bc6fSJiri Pirko 
2028fb4bc6fSJiri Pirko 	devlink = devlink_alloc(&nsim_dev_devlink_ops, sizeof(*nsim_dev));
2038fb4bc6fSJiri Pirko 	if (!devlink)
204a60f9e48SJiri Pirko 		return ERR_PTR(-ENOMEM);
2058fb4bc6fSJiri Pirko 	nsim_dev = devlink_priv(devlink);
206*d514f41eSJiri Pirko 	nsim_dev->nsim_bus_dev = nsim_bus_dev;
2078fb4bc6fSJiri Pirko 
2088fb4bc6fSJiri Pirko 	nsim_dev->fib_data = nsim_fib_create();
2098fb4bc6fSJiri Pirko 	if (IS_ERR(nsim_dev->fib_data)) {
2108fb4bc6fSJiri Pirko 		err = PTR_ERR(nsim_dev->fib_data);
2118fb4bc6fSJiri Pirko 		goto err_devlink_free;
2128fb4bc6fSJiri Pirko 	}
2138fb4bc6fSJiri Pirko 
2148fb4bc6fSJiri Pirko 	err = nsim_dev_resources_register(devlink);
2158fb4bc6fSJiri Pirko 	if (err)
2168fb4bc6fSJiri Pirko 		goto err_fib_destroy;
2178fb4bc6fSJiri Pirko 
218a60f9e48SJiri Pirko 	err = devlink_register(devlink, &nsim_bus_dev->dev);
2198fb4bc6fSJiri Pirko 	if (err)
2208fb4bc6fSJiri Pirko 		goto err_resources_unregister;
2218fb4bc6fSJiri Pirko 
222*d514f41eSJiri Pirko 	err = nsim_dev_debugfs_init(nsim_dev);
223*d514f41eSJiri Pirko 	if (err)
224*d514f41eSJiri Pirko 		goto err_dl_unregister;
225*d514f41eSJiri Pirko 
226*d514f41eSJiri Pirko 	err = nsim_bpf_dev_init(nsim_dev);
227*d514f41eSJiri Pirko 	if (err)
228*d514f41eSJiri Pirko 		goto err_debugfs_exit;
229*d514f41eSJiri Pirko 
230a60f9e48SJiri Pirko 	return nsim_dev;
2318fb4bc6fSJiri Pirko 
232*d514f41eSJiri Pirko err_debugfs_exit:
233*d514f41eSJiri Pirko 	nsim_dev_debugfs_exit(nsim_dev);
234*d514f41eSJiri Pirko err_dl_unregister:
235*d514f41eSJiri Pirko 	devlink_unregister(devlink);
2368fb4bc6fSJiri Pirko err_resources_unregister:
2378fb4bc6fSJiri Pirko 	devlink_resources_unregister(devlink, NULL);
2388fb4bc6fSJiri Pirko err_fib_destroy:
2398fb4bc6fSJiri Pirko 	nsim_fib_destroy(nsim_dev->fib_data);
2408fb4bc6fSJiri Pirko err_devlink_free:
2418fb4bc6fSJiri Pirko 	devlink_free(devlink);
242a60f9e48SJiri Pirko 	return ERR_PTR(err);
2438fb4bc6fSJiri Pirko }
2448fb4bc6fSJiri Pirko 
245a60f9e48SJiri Pirko struct nsim_dev *
246a60f9e48SJiri Pirko nsim_dev_create_with_ns(struct nsim_bus_dev *nsim_bus_dev,
247a60f9e48SJiri Pirko 			struct netdevsim *ns)
2488fb4bc6fSJiri Pirko {
249a60f9e48SJiri Pirko 	struct nsim_dev *nsim_dev;
2508fb4bc6fSJiri Pirko 
2518fb4bc6fSJiri Pirko 	dev_hold(ns->netdev);
2528fb4bc6fSJiri Pirko 	rtnl_unlock();
253a60f9e48SJiri Pirko 	nsim_dev = nsim_dev_create(nsim_bus_dev);
2548fb4bc6fSJiri Pirko 	rtnl_lock();
2558fb4bc6fSJiri Pirko 	dev_put(ns->netdev);
256a60f9e48SJiri Pirko 	return nsim_dev;
2578fb4bc6fSJiri Pirko }
2588fb4bc6fSJiri Pirko 
259a60f9e48SJiri Pirko void nsim_dev_destroy(struct nsim_dev *nsim_dev)
2608fb4bc6fSJiri Pirko {
261a60f9e48SJiri Pirko 	struct devlink *devlink = priv_to_devlink(nsim_dev);
2628fb4bc6fSJiri Pirko 
263*d514f41eSJiri Pirko 	nsim_bpf_dev_exit(nsim_dev);
264*d514f41eSJiri Pirko 	nsim_dev_debugfs_exit(nsim_dev);
2658fb4bc6fSJiri Pirko 	devlink_unregister(devlink);
2668fb4bc6fSJiri Pirko 	devlink_resources_unregister(devlink, NULL);
2678fb4bc6fSJiri Pirko 	nsim_fib_destroy(nsim_dev->fib_data);
2688fb4bc6fSJiri Pirko 	devlink_free(devlink);
2698fb4bc6fSJiri Pirko }
270*d514f41eSJiri Pirko 
271*d514f41eSJiri Pirko int nsim_dev_init(void)
272*d514f41eSJiri Pirko {
273*d514f41eSJiri Pirko 	nsim_dev_ddir = debugfs_create_dir(DRV_NAME "_dev", NULL);
274*d514f41eSJiri Pirko 	if (IS_ERR_OR_NULL(nsim_dev_ddir))
275*d514f41eSJiri Pirko 		return -ENOMEM;
276*d514f41eSJiri Pirko 	return 0;
277*d514f41eSJiri Pirko }
278*d514f41eSJiri Pirko 
279*d514f41eSJiri Pirko void nsim_dev_exit(void)
280*d514f41eSJiri Pirko {
281*d514f41eSJiri Pirko 	debugfs_remove_recursive(nsim_dev_ddir);
282*d514f41eSJiri Pirko }
283