xref: /linux-6.15/drivers/net/netdevsim/dev.c (revision a60f9e48)
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 
188fb4bc6fSJiri Pirko #include <linux/device.h>
198fb4bc6fSJiri Pirko #include <linux/rtnetlink.h>
208fb4bc6fSJiri Pirko #include <net/devlink.h>
218fb4bc6fSJiri Pirko 
228fb4bc6fSJiri Pirko #include "netdevsim.h"
238fb4bc6fSJiri Pirko 
248fb4bc6fSJiri Pirko static u64 nsim_dev_ipv4_fib_resource_occ_get(void *priv)
258fb4bc6fSJiri Pirko {
268fb4bc6fSJiri Pirko 	struct nsim_dev *nsim_dev = priv;
278fb4bc6fSJiri Pirko 
288fb4bc6fSJiri Pirko 	return nsim_fib_get_val(nsim_dev->fib_data,
298fb4bc6fSJiri Pirko 				NSIM_RESOURCE_IPV4_FIB, false);
308fb4bc6fSJiri Pirko }
318fb4bc6fSJiri Pirko 
328fb4bc6fSJiri Pirko static u64 nsim_dev_ipv4_fib_rules_res_occ_get(void *priv)
338fb4bc6fSJiri Pirko {
348fb4bc6fSJiri Pirko 	struct nsim_dev *nsim_dev = priv;
358fb4bc6fSJiri Pirko 
368fb4bc6fSJiri Pirko 	return nsim_fib_get_val(nsim_dev->fib_data,
378fb4bc6fSJiri Pirko 				NSIM_RESOURCE_IPV4_FIB_RULES, false);
388fb4bc6fSJiri Pirko }
398fb4bc6fSJiri Pirko 
408fb4bc6fSJiri Pirko static u64 nsim_dev_ipv6_fib_resource_occ_get(void *priv)
418fb4bc6fSJiri Pirko {
428fb4bc6fSJiri Pirko 	struct nsim_dev *nsim_dev = priv;
438fb4bc6fSJiri Pirko 
448fb4bc6fSJiri Pirko 	return nsim_fib_get_val(nsim_dev->fib_data,
458fb4bc6fSJiri Pirko 				NSIM_RESOURCE_IPV6_FIB, false);
468fb4bc6fSJiri Pirko }
478fb4bc6fSJiri Pirko 
488fb4bc6fSJiri Pirko static u64 nsim_dev_ipv6_fib_rules_res_occ_get(void *priv)
498fb4bc6fSJiri Pirko {
508fb4bc6fSJiri Pirko 	struct nsim_dev *nsim_dev = priv;
518fb4bc6fSJiri Pirko 
528fb4bc6fSJiri Pirko 	return nsim_fib_get_val(nsim_dev->fib_data,
538fb4bc6fSJiri Pirko 				NSIM_RESOURCE_IPV6_FIB_RULES, false);
548fb4bc6fSJiri Pirko }
558fb4bc6fSJiri Pirko 
568fb4bc6fSJiri Pirko static int nsim_dev_resources_register(struct devlink *devlink)
578fb4bc6fSJiri Pirko {
588fb4bc6fSJiri Pirko 	struct nsim_dev *nsim_dev = devlink_priv(devlink);
598fb4bc6fSJiri Pirko 	struct devlink_resource_size_params params = {
608fb4bc6fSJiri Pirko 		.size_max = (u64)-1,
618fb4bc6fSJiri Pirko 		.size_granularity = 1,
628fb4bc6fSJiri Pirko 		.unit = DEVLINK_RESOURCE_UNIT_ENTRY
638fb4bc6fSJiri Pirko 	};
648fb4bc6fSJiri Pirko 	int err;
658fb4bc6fSJiri Pirko 	u64 n;
668fb4bc6fSJiri Pirko 
678fb4bc6fSJiri Pirko 	/* Resources for IPv4 */
688fb4bc6fSJiri Pirko 	err = devlink_resource_register(devlink, "IPv4", (u64)-1,
698fb4bc6fSJiri Pirko 					NSIM_RESOURCE_IPV4,
708fb4bc6fSJiri Pirko 					DEVLINK_RESOURCE_ID_PARENT_TOP,
718fb4bc6fSJiri Pirko 					&params);
728fb4bc6fSJiri Pirko 	if (err) {
738fb4bc6fSJiri Pirko 		pr_err("Failed to register IPv4 top resource\n");
748fb4bc6fSJiri Pirko 		goto out;
758fb4bc6fSJiri Pirko 	}
768fb4bc6fSJiri Pirko 
778fb4bc6fSJiri Pirko 	n = nsim_fib_get_val(nsim_dev->fib_data,
788fb4bc6fSJiri Pirko 			     NSIM_RESOURCE_IPV4_FIB, true);
798fb4bc6fSJiri Pirko 	err = devlink_resource_register(devlink, "fib", n,
808fb4bc6fSJiri Pirko 					NSIM_RESOURCE_IPV4_FIB,
818fb4bc6fSJiri Pirko 					NSIM_RESOURCE_IPV4, &params);
828fb4bc6fSJiri Pirko 	if (err) {
838fb4bc6fSJiri Pirko 		pr_err("Failed to register IPv4 FIB resource\n");
848fb4bc6fSJiri Pirko 		return err;
858fb4bc6fSJiri Pirko 	}
868fb4bc6fSJiri Pirko 
878fb4bc6fSJiri Pirko 	n = nsim_fib_get_val(nsim_dev->fib_data,
888fb4bc6fSJiri Pirko 			     NSIM_RESOURCE_IPV4_FIB_RULES, true);
898fb4bc6fSJiri Pirko 	err = devlink_resource_register(devlink, "fib-rules", n,
908fb4bc6fSJiri Pirko 					NSIM_RESOURCE_IPV4_FIB_RULES,
918fb4bc6fSJiri Pirko 					NSIM_RESOURCE_IPV4, &params);
928fb4bc6fSJiri Pirko 	if (err) {
938fb4bc6fSJiri Pirko 		pr_err("Failed to register IPv4 FIB rules resource\n");
948fb4bc6fSJiri Pirko 		return err;
958fb4bc6fSJiri Pirko 	}
968fb4bc6fSJiri Pirko 
978fb4bc6fSJiri Pirko 	/* Resources for IPv6 */
988fb4bc6fSJiri Pirko 	err = devlink_resource_register(devlink, "IPv6", (u64)-1,
998fb4bc6fSJiri Pirko 					NSIM_RESOURCE_IPV6,
1008fb4bc6fSJiri Pirko 					DEVLINK_RESOURCE_ID_PARENT_TOP,
1018fb4bc6fSJiri Pirko 					&params);
1028fb4bc6fSJiri Pirko 	if (err) {
1038fb4bc6fSJiri Pirko 		pr_err("Failed to register IPv6 top resource\n");
1048fb4bc6fSJiri Pirko 		goto out;
1058fb4bc6fSJiri Pirko 	}
1068fb4bc6fSJiri Pirko 
1078fb4bc6fSJiri Pirko 	n = nsim_fib_get_val(nsim_dev->fib_data,
1088fb4bc6fSJiri Pirko 			     NSIM_RESOURCE_IPV6_FIB, true);
1098fb4bc6fSJiri Pirko 	err = devlink_resource_register(devlink, "fib", n,
1108fb4bc6fSJiri Pirko 					NSIM_RESOURCE_IPV6_FIB,
1118fb4bc6fSJiri Pirko 					NSIM_RESOURCE_IPV6, &params);
1128fb4bc6fSJiri Pirko 	if (err) {
1138fb4bc6fSJiri Pirko 		pr_err("Failed to register IPv6 FIB resource\n");
1148fb4bc6fSJiri Pirko 		return err;
1158fb4bc6fSJiri Pirko 	}
1168fb4bc6fSJiri Pirko 
1178fb4bc6fSJiri Pirko 	n = nsim_fib_get_val(nsim_dev->fib_data,
1188fb4bc6fSJiri Pirko 			     NSIM_RESOURCE_IPV6_FIB_RULES, true);
1198fb4bc6fSJiri Pirko 	err = devlink_resource_register(devlink, "fib-rules", n,
1208fb4bc6fSJiri Pirko 					NSIM_RESOURCE_IPV6_FIB_RULES,
1218fb4bc6fSJiri Pirko 					NSIM_RESOURCE_IPV6, &params);
1228fb4bc6fSJiri Pirko 	if (err) {
1238fb4bc6fSJiri Pirko 		pr_err("Failed to register IPv6 FIB rules resource\n");
1248fb4bc6fSJiri Pirko 		return err;
1258fb4bc6fSJiri Pirko 	}
1268fb4bc6fSJiri Pirko 
1278fb4bc6fSJiri Pirko 	devlink_resource_occ_get_register(devlink,
1288fb4bc6fSJiri Pirko 					  NSIM_RESOURCE_IPV4_FIB,
1298fb4bc6fSJiri Pirko 					  nsim_dev_ipv4_fib_resource_occ_get,
1308fb4bc6fSJiri Pirko 					  nsim_dev);
1318fb4bc6fSJiri Pirko 	devlink_resource_occ_get_register(devlink,
1328fb4bc6fSJiri Pirko 					  NSIM_RESOURCE_IPV4_FIB_RULES,
1338fb4bc6fSJiri Pirko 					  nsim_dev_ipv4_fib_rules_res_occ_get,
1348fb4bc6fSJiri Pirko 					  nsim_dev);
1358fb4bc6fSJiri Pirko 	devlink_resource_occ_get_register(devlink,
1368fb4bc6fSJiri Pirko 					  NSIM_RESOURCE_IPV6_FIB,
1378fb4bc6fSJiri Pirko 					  nsim_dev_ipv6_fib_resource_occ_get,
1388fb4bc6fSJiri Pirko 					  nsim_dev);
1398fb4bc6fSJiri Pirko 	devlink_resource_occ_get_register(devlink,
1408fb4bc6fSJiri Pirko 					  NSIM_RESOURCE_IPV6_FIB_RULES,
1418fb4bc6fSJiri Pirko 					  nsim_dev_ipv6_fib_rules_res_occ_get,
1428fb4bc6fSJiri Pirko 					  nsim_dev);
1438fb4bc6fSJiri Pirko out:
1448fb4bc6fSJiri Pirko 	return err;
1458fb4bc6fSJiri Pirko }
1468fb4bc6fSJiri Pirko 
1478fb4bc6fSJiri Pirko static int nsim_dev_reload(struct devlink *devlink,
1488fb4bc6fSJiri Pirko 			   struct netlink_ext_ack *extack)
1498fb4bc6fSJiri Pirko {
1508fb4bc6fSJiri Pirko 	struct nsim_dev *nsim_dev = devlink_priv(devlink);
1518fb4bc6fSJiri Pirko 	enum nsim_resource_id res_ids[] = {
1528fb4bc6fSJiri Pirko 		NSIM_RESOURCE_IPV4_FIB, NSIM_RESOURCE_IPV4_FIB_RULES,
1538fb4bc6fSJiri Pirko 		NSIM_RESOURCE_IPV6_FIB, NSIM_RESOURCE_IPV6_FIB_RULES
1548fb4bc6fSJiri Pirko 	};
1558fb4bc6fSJiri Pirko 	int i;
1568fb4bc6fSJiri Pirko 
1578fb4bc6fSJiri Pirko 	for (i = 0; i < ARRAY_SIZE(res_ids); ++i) {
1588fb4bc6fSJiri Pirko 		int err;
1598fb4bc6fSJiri Pirko 		u64 val;
1608fb4bc6fSJiri Pirko 
1618fb4bc6fSJiri Pirko 		err = devlink_resource_size_get(devlink, res_ids[i], &val);
1628fb4bc6fSJiri Pirko 		if (!err) {
1638fb4bc6fSJiri Pirko 			err = nsim_fib_set_max(nsim_dev->fib_data,
1648fb4bc6fSJiri Pirko 					       res_ids[i], val, extack);
1658fb4bc6fSJiri Pirko 			if (err)
1668fb4bc6fSJiri Pirko 				return err;
1678fb4bc6fSJiri Pirko 		}
1688fb4bc6fSJiri Pirko 	}
1698fb4bc6fSJiri Pirko 
1708fb4bc6fSJiri Pirko 	return 0;
1718fb4bc6fSJiri Pirko }
1728fb4bc6fSJiri Pirko 
1738fb4bc6fSJiri Pirko static const struct devlink_ops nsim_dev_devlink_ops = {
1748fb4bc6fSJiri Pirko 	.reload = nsim_dev_reload,
1758fb4bc6fSJiri Pirko };
1768fb4bc6fSJiri Pirko 
177*a60f9e48SJiri Pirko static struct nsim_dev *nsim_dev_create(struct nsim_bus_dev *nsim_bus_dev)
1788fb4bc6fSJiri Pirko {
1798fb4bc6fSJiri Pirko 	struct nsim_dev *nsim_dev;
1808fb4bc6fSJiri Pirko 	struct devlink *devlink;
1818fb4bc6fSJiri Pirko 	int err;
1828fb4bc6fSJiri Pirko 
1838fb4bc6fSJiri Pirko 	devlink = devlink_alloc(&nsim_dev_devlink_ops, sizeof(*nsim_dev));
1848fb4bc6fSJiri Pirko 	if (!devlink)
185*a60f9e48SJiri Pirko 		return ERR_PTR(-ENOMEM);
1868fb4bc6fSJiri Pirko 	nsim_dev = devlink_priv(devlink);
1878fb4bc6fSJiri Pirko 
1888fb4bc6fSJiri Pirko 	nsim_dev->fib_data = nsim_fib_create();
1898fb4bc6fSJiri Pirko 	if (IS_ERR(nsim_dev->fib_data)) {
1908fb4bc6fSJiri Pirko 		err = PTR_ERR(nsim_dev->fib_data);
1918fb4bc6fSJiri Pirko 		goto err_devlink_free;
1928fb4bc6fSJiri Pirko 	}
1938fb4bc6fSJiri Pirko 
1948fb4bc6fSJiri Pirko 	err = nsim_dev_resources_register(devlink);
1958fb4bc6fSJiri Pirko 	if (err)
1968fb4bc6fSJiri Pirko 		goto err_fib_destroy;
1978fb4bc6fSJiri Pirko 
198*a60f9e48SJiri Pirko 	err = devlink_register(devlink, &nsim_bus_dev->dev);
1998fb4bc6fSJiri Pirko 	if (err)
2008fb4bc6fSJiri Pirko 		goto err_resources_unregister;
2018fb4bc6fSJiri Pirko 
202*a60f9e48SJiri Pirko 	return nsim_dev;
2038fb4bc6fSJiri Pirko 
2048fb4bc6fSJiri Pirko err_resources_unregister:
2058fb4bc6fSJiri Pirko 	devlink_resources_unregister(devlink, NULL);
2068fb4bc6fSJiri Pirko err_fib_destroy:
2078fb4bc6fSJiri Pirko 	nsim_fib_destroy(nsim_dev->fib_data);
2088fb4bc6fSJiri Pirko err_devlink_free:
2098fb4bc6fSJiri Pirko 	devlink_free(devlink);
210*a60f9e48SJiri Pirko 	return ERR_PTR(err);
2118fb4bc6fSJiri Pirko }
2128fb4bc6fSJiri Pirko 
213*a60f9e48SJiri Pirko struct nsim_dev *
214*a60f9e48SJiri Pirko nsim_dev_create_with_ns(struct nsim_bus_dev *nsim_bus_dev,
215*a60f9e48SJiri Pirko 			struct netdevsim *ns)
2168fb4bc6fSJiri Pirko {
217*a60f9e48SJiri Pirko 	struct nsim_dev *nsim_dev;
2188fb4bc6fSJiri Pirko 
2198fb4bc6fSJiri Pirko 	dev_hold(ns->netdev);
2208fb4bc6fSJiri Pirko 	rtnl_unlock();
221*a60f9e48SJiri Pirko 	nsim_dev = nsim_dev_create(nsim_bus_dev);
2228fb4bc6fSJiri Pirko 	rtnl_lock();
2238fb4bc6fSJiri Pirko 	dev_put(ns->netdev);
224*a60f9e48SJiri Pirko 	return nsim_dev;
2258fb4bc6fSJiri Pirko }
2268fb4bc6fSJiri Pirko 
227*a60f9e48SJiri Pirko void nsim_dev_destroy(struct nsim_dev *nsim_dev)
2288fb4bc6fSJiri Pirko {
229*a60f9e48SJiri Pirko 	struct devlink *devlink = priv_to_devlink(nsim_dev);
2308fb4bc6fSJiri Pirko 
2318fb4bc6fSJiri Pirko 	devlink_unregister(devlink);
2328fb4bc6fSJiri Pirko 	devlink_resources_unregister(devlink, NULL);
2338fb4bc6fSJiri Pirko 	nsim_fib_destroy(nsim_dev->fib_data);
2348fb4bc6fSJiri Pirko 	devlink_free(devlink);
2358fb4bc6fSJiri Pirko }
236