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