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 ¶ms); 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, ¶ms); 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, ¶ms); 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 ¶ms); 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, ¶ms); 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, ¶ms); 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