1*8fb4bc6fSJiri Pirko /* 2*8fb4bc6fSJiri Pirko * Copyright (c) 2018 Cumulus Networks. All rights reserved. 3*8fb4bc6fSJiri Pirko * Copyright (c) 2018 David Ahern <[email protected]> 4*8fb4bc6fSJiri Pirko * Copyright (c) 2019 Mellanox Technologies. All rights reserved. 5*8fb4bc6fSJiri Pirko * 6*8fb4bc6fSJiri Pirko * This software is licensed under the GNU General License Version 2, 7*8fb4bc6fSJiri Pirko * June 1991 as shown in the file COPYING in the top-level directory of this 8*8fb4bc6fSJiri Pirko * source tree. 9*8fb4bc6fSJiri Pirko * 10*8fb4bc6fSJiri Pirko * THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" 11*8fb4bc6fSJiri Pirko * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, 12*8fb4bc6fSJiri Pirko * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 13*8fb4bc6fSJiri Pirko * FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE 14*8fb4bc6fSJiri Pirko * OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME 15*8fb4bc6fSJiri Pirko * THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16*8fb4bc6fSJiri Pirko */ 17*8fb4bc6fSJiri Pirko 18*8fb4bc6fSJiri Pirko #include <linux/device.h> 19*8fb4bc6fSJiri Pirko #include <linux/rtnetlink.h> 20*8fb4bc6fSJiri Pirko #include <net/devlink.h> 21*8fb4bc6fSJiri Pirko 22*8fb4bc6fSJiri Pirko #include "netdevsim.h" 23*8fb4bc6fSJiri Pirko 24*8fb4bc6fSJiri Pirko struct nsim_dev { 25*8fb4bc6fSJiri Pirko struct nsim_fib_data *fib_data; 26*8fb4bc6fSJiri Pirko }; 27*8fb4bc6fSJiri Pirko 28*8fb4bc6fSJiri Pirko static u64 nsim_dev_ipv4_fib_resource_occ_get(void *priv) 29*8fb4bc6fSJiri Pirko { 30*8fb4bc6fSJiri Pirko struct nsim_dev *nsim_dev = priv; 31*8fb4bc6fSJiri Pirko 32*8fb4bc6fSJiri Pirko return nsim_fib_get_val(nsim_dev->fib_data, 33*8fb4bc6fSJiri Pirko NSIM_RESOURCE_IPV4_FIB, false); 34*8fb4bc6fSJiri Pirko } 35*8fb4bc6fSJiri Pirko 36*8fb4bc6fSJiri Pirko static u64 nsim_dev_ipv4_fib_rules_res_occ_get(void *priv) 37*8fb4bc6fSJiri Pirko { 38*8fb4bc6fSJiri Pirko struct nsim_dev *nsim_dev = priv; 39*8fb4bc6fSJiri Pirko 40*8fb4bc6fSJiri Pirko return nsim_fib_get_val(nsim_dev->fib_data, 41*8fb4bc6fSJiri Pirko NSIM_RESOURCE_IPV4_FIB_RULES, false); 42*8fb4bc6fSJiri Pirko } 43*8fb4bc6fSJiri Pirko 44*8fb4bc6fSJiri Pirko static u64 nsim_dev_ipv6_fib_resource_occ_get(void *priv) 45*8fb4bc6fSJiri Pirko { 46*8fb4bc6fSJiri Pirko struct nsim_dev *nsim_dev = priv; 47*8fb4bc6fSJiri Pirko 48*8fb4bc6fSJiri Pirko return nsim_fib_get_val(nsim_dev->fib_data, 49*8fb4bc6fSJiri Pirko NSIM_RESOURCE_IPV6_FIB, false); 50*8fb4bc6fSJiri Pirko } 51*8fb4bc6fSJiri Pirko 52*8fb4bc6fSJiri Pirko static u64 nsim_dev_ipv6_fib_rules_res_occ_get(void *priv) 53*8fb4bc6fSJiri Pirko { 54*8fb4bc6fSJiri Pirko struct nsim_dev *nsim_dev = priv; 55*8fb4bc6fSJiri Pirko 56*8fb4bc6fSJiri Pirko return nsim_fib_get_val(nsim_dev->fib_data, 57*8fb4bc6fSJiri Pirko NSIM_RESOURCE_IPV6_FIB_RULES, false); 58*8fb4bc6fSJiri Pirko } 59*8fb4bc6fSJiri Pirko 60*8fb4bc6fSJiri Pirko static int nsim_dev_resources_register(struct devlink *devlink) 61*8fb4bc6fSJiri Pirko { 62*8fb4bc6fSJiri Pirko struct nsim_dev *nsim_dev = devlink_priv(devlink); 63*8fb4bc6fSJiri Pirko struct devlink_resource_size_params params = { 64*8fb4bc6fSJiri Pirko .size_max = (u64)-1, 65*8fb4bc6fSJiri Pirko .size_granularity = 1, 66*8fb4bc6fSJiri Pirko .unit = DEVLINK_RESOURCE_UNIT_ENTRY 67*8fb4bc6fSJiri Pirko }; 68*8fb4bc6fSJiri Pirko int err; 69*8fb4bc6fSJiri Pirko u64 n; 70*8fb4bc6fSJiri Pirko 71*8fb4bc6fSJiri Pirko /* Resources for IPv4 */ 72*8fb4bc6fSJiri Pirko err = devlink_resource_register(devlink, "IPv4", (u64)-1, 73*8fb4bc6fSJiri Pirko NSIM_RESOURCE_IPV4, 74*8fb4bc6fSJiri Pirko DEVLINK_RESOURCE_ID_PARENT_TOP, 75*8fb4bc6fSJiri Pirko ¶ms); 76*8fb4bc6fSJiri Pirko if (err) { 77*8fb4bc6fSJiri Pirko pr_err("Failed to register IPv4 top resource\n"); 78*8fb4bc6fSJiri Pirko goto out; 79*8fb4bc6fSJiri Pirko } 80*8fb4bc6fSJiri Pirko 81*8fb4bc6fSJiri Pirko n = nsim_fib_get_val(nsim_dev->fib_data, 82*8fb4bc6fSJiri Pirko NSIM_RESOURCE_IPV4_FIB, true); 83*8fb4bc6fSJiri Pirko err = devlink_resource_register(devlink, "fib", n, 84*8fb4bc6fSJiri Pirko NSIM_RESOURCE_IPV4_FIB, 85*8fb4bc6fSJiri Pirko NSIM_RESOURCE_IPV4, ¶ms); 86*8fb4bc6fSJiri Pirko if (err) { 87*8fb4bc6fSJiri Pirko pr_err("Failed to register IPv4 FIB resource\n"); 88*8fb4bc6fSJiri Pirko return err; 89*8fb4bc6fSJiri Pirko } 90*8fb4bc6fSJiri Pirko 91*8fb4bc6fSJiri Pirko n = nsim_fib_get_val(nsim_dev->fib_data, 92*8fb4bc6fSJiri Pirko NSIM_RESOURCE_IPV4_FIB_RULES, true); 93*8fb4bc6fSJiri Pirko err = devlink_resource_register(devlink, "fib-rules", n, 94*8fb4bc6fSJiri Pirko NSIM_RESOURCE_IPV4_FIB_RULES, 95*8fb4bc6fSJiri Pirko NSIM_RESOURCE_IPV4, ¶ms); 96*8fb4bc6fSJiri Pirko if (err) { 97*8fb4bc6fSJiri Pirko pr_err("Failed to register IPv4 FIB rules resource\n"); 98*8fb4bc6fSJiri Pirko return err; 99*8fb4bc6fSJiri Pirko } 100*8fb4bc6fSJiri Pirko 101*8fb4bc6fSJiri Pirko /* Resources for IPv6 */ 102*8fb4bc6fSJiri Pirko err = devlink_resource_register(devlink, "IPv6", (u64)-1, 103*8fb4bc6fSJiri Pirko NSIM_RESOURCE_IPV6, 104*8fb4bc6fSJiri Pirko DEVLINK_RESOURCE_ID_PARENT_TOP, 105*8fb4bc6fSJiri Pirko ¶ms); 106*8fb4bc6fSJiri Pirko if (err) { 107*8fb4bc6fSJiri Pirko pr_err("Failed to register IPv6 top resource\n"); 108*8fb4bc6fSJiri Pirko goto out; 109*8fb4bc6fSJiri Pirko } 110*8fb4bc6fSJiri Pirko 111*8fb4bc6fSJiri Pirko n = nsim_fib_get_val(nsim_dev->fib_data, 112*8fb4bc6fSJiri Pirko NSIM_RESOURCE_IPV6_FIB, true); 113*8fb4bc6fSJiri Pirko err = devlink_resource_register(devlink, "fib", n, 114*8fb4bc6fSJiri Pirko NSIM_RESOURCE_IPV6_FIB, 115*8fb4bc6fSJiri Pirko NSIM_RESOURCE_IPV6, ¶ms); 116*8fb4bc6fSJiri Pirko if (err) { 117*8fb4bc6fSJiri Pirko pr_err("Failed to register IPv6 FIB resource\n"); 118*8fb4bc6fSJiri Pirko return err; 119*8fb4bc6fSJiri Pirko } 120*8fb4bc6fSJiri Pirko 121*8fb4bc6fSJiri Pirko n = nsim_fib_get_val(nsim_dev->fib_data, 122*8fb4bc6fSJiri Pirko NSIM_RESOURCE_IPV6_FIB_RULES, true); 123*8fb4bc6fSJiri Pirko err = devlink_resource_register(devlink, "fib-rules", n, 124*8fb4bc6fSJiri Pirko NSIM_RESOURCE_IPV6_FIB_RULES, 125*8fb4bc6fSJiri Pirko NSIM_RESOURCE_IPV6, ¶ms); 126*8fb4bc6fSJiri Pirko if (err) { 127*8fb4bc6fSJiri Pirko pr_err("Failed to register IPv6 FIB rules resource\n"); 128*8fb4bc6fSJiri Pirko return err; 129*8fb4bc6fSJiri Pirko } 130*8fb4bc6fSJiri Pirko 131*8fb4bc6fSJiri Pirko devlink_resource_occ_get_register(devlink, 132*8fb4bc6fSJiri Pirko NSIM_RESOURCE_IPV4_FIB, 133*8fb4bc6fSJiri Pirko nsim_dev_ipv4_fib_resource_occ_get, 134*8fb4bc6fSJiri Pirko nsim_dev); 135*8fb4bc6fSJiri Pirko devlink_resource_occ_get_register(devlink, 136*8fb4bc6fSJiri Pirko NSIM_RESOURCE_IPV4_FIB_RULES, 137*8fb4bc6fSJiri Pirko nsim_dev_ipv4_fib_rules_res_occ_get, 138*8fb4bc6fSJiri Pirko nsim_dev); 139*8fb4bc6fSJiri Pirko devlink_resource_occ_get_register(devlink, 140*8fb4bc6fSJiri Pirko NSIM_RESOURCE_IPV6_FIB, 141*8fb4bc6fSJiri Pirko nsim_dev_ipv6_fib_resource_occ_get, 142*8fb4bc6fSJiri Pirko nsim_dev); 143*8fb4bc6fSJiri Pirko devlink_resource_occ_get_register(devlink, 144*8fb4bc6fSJiri Pirko NSIM_RESOURCE_IPV6_FIB_RULES, 145*8fb4bc6fSJiri Pirko nsim_dev_ipv6_fib_rules_res_occ_get, 146*8fb4bc6fSJiri Pirko nsim_dev); 147*8fb4bc6fSJiri Pirko out: 148*8fb4bc6fSJiri Pirko return err; 149*8fb4bc6fSJiri Pirko } 150*8fb4bc6fSJiri Pirko 151*8fb4bc6fSJiri Pirko static int nsim_dev_reload(struct devlink *devlink, 152*8fb4bc6fSJiri Pirko struct netlink_ext_ack *extack) 153*8fb4bc6fSJiri Pirko { 154*8fb4bc6fSJiri Pirko struct nsim_dev *nsim_dev = devlink_priv(devlink); 155*8fb4bc6fSJiri Pirko enum nsim_resource_id res_ids[] = { 156*8fb4bc6fSJiri Pirko NSIM_RESOURCE_IPV4_FIB, NSIM_RESOURCE_IPV4_FIB_RULES, 157*8fb4bc6fSJiri Pirko NSIM_RESOURCE_IPV6_FIB, NSIM_RESOURCE_IPV6_FIB_RULES 158*8fb4bc6fSJiri Pirko }; 159*8fb4bc6fSJiri Pirko int i; 160*8fb4bc6fSJiri Pirko 161*8fb4bc6fSJiri Pirko for (i = 0; i < ARRAY_SIZE(res_ids); ++i) { 162*8fb4bc6fSJiri Pirko int err; 163*8fb4bc6fSJiri Pirko u64 val; 164*8fb4bc6fSJiri Pirko 165*8fb4bc6fSJiri Pirko err = devlink_resource_size_get(devlink, res_ids[i], &val); 166*8fb4bc6fSJiri Pirko if (!err) { 167*8fb4bc6fSJiri Pirko err = nsim_fib_set_max(nsim_dev->fib_data, 168*8fb4bc6fSJiri Pirko res_ids[i], val, extack); 169*8fb4bc6fSJiri Pirko if (err) 170*8fb4bc6fSJiri Pirko return err; 171*8fb4bc6fSJiri Pirko } 172*8fb4bc6fSJiri Pirko } 173*8fb4bc6fSJiri Pirko 174*8fb4bc6fSJiri Pirko return 0; 175*8fb4bc6fSJiri Pirko } 176*8fb4bc6fSJiri Pirko 177*8fb4bc6fSJiri Pirko static const struct devlink_ops nsim_dev_devlink_ops = { 178*8fb4bc6fSJiri Pirko .reload = nsim_dev_reload, 179*8fb4bc6fSJiri Pirko }; 180*8fb4bc6fSJiri Pirko 181*8fb4bc6fSJiri Pirko static int __nsim_dev_init(struct netdevsim *ns) 182*8fb4bc6fSJiri Pirko { 183*8fb4bc6fSJiri Pirko struct nsim_dev *nsim_dev; 184*8fb4bc6fSJiri Pirko struct devlink *devlink; 185*8fb4bc6fSJiri Pirko int err; 186*8fb4bc6fSJiri Pirko 187*8fb4bc6fSJiri Pirko devlink = devlink_alloc(&nsim_dev_devlink_ops, sizeof(*nsim_dev)); 188*8fb4bc6fSJiri Pirko if (!devlink) 189*8fb4bc6fSJiri Pirko return -ENOMEM; 190*8fb4bc6fSJiri Pirko nsim_dev = devlink_priv(devlink); 191*8fb4bc6fSJiri Pirko 192*8fb4bc6fSJiri Pirko nsim_dev->fib_data = nsim_fib_create(); 193*8fb4bc6fSJiri Pirko if (IS_ERR(nsim_dev->fib_data)) { 194*8fb4bc6fSJiri Pirko err = PTR_ERR(nsim_dev->fib_data); 195*8fb4bc6fSJiri Pirko goto err_devlink_free; 196*8fb4bc6fSJiri Pirko } 197*8fb4bc6fSJiri Pirko 198*8fb4bc6fSJiri Pirko err = nsim_dev_resources_register(devlink); 199*8fb4bc6fSJiri Pirko if (err) 200*8fb4bc6fSJiri Pirko goto err_fib_destroy; 201*8fb4bc6fSJiri Pirko 202*8fb4bc6fSJiri Pirko err = devlink_register(devlink, &ns->dev); 203*8fb4bc6fSJiri Pirko if (err) 204*8fb4bc6fSJiri Pirko goto err_resources_unregister; 205*8fb4bc6fSJiri Pirko 206*8fb4bc6fSJiri Pirko ns->devlink = devlink; 207*8fb4bc6fSJiri Pirko 208*8fb4bc6fSJiri Pirko return 0; 209*8fb4bc6fSJiri Pirko 210*8fb4bc6fSJiri Pirko err_resources_unregister: 211*8fb4bc6fSJiri Pirko devlink_resources_unregister(devlink, NULL); 212*8fb4bc6fSJiri Pirko err_fib_destroy: 213*8fb4bc6fSJiri Pirko nsim_fib_destroy(nsim_dev->fib_data); 214*8fb4bc6fSJiri Pirko err_devlink_free: 215*8fb4bc6fSJiri Pirko devlink_free(devlink); 216*8fb4bc6fSJiri Pirko 217*8fb4bc6fSJiri Pirko return err; 218*8fb4bc6fSJiri Pirko } 219*8fb4bc6fSJiri Pirko 220*8fb4bc6fSJiri Pirko int nsim_dev_init(struct netdevsim *ns) 221*8fb4bc6fSJiri Pirko { 222*8fb4bc6fSJiri Pirko int err; 223*8fb4bc6fSJiri Pirko 224*8fb4bc6fSJiri Pirko dev_hold(ns->netdev); 225*8fb4bc6fSJiri Pirko rtnl_unlock(); 226*8fb4bc6fSJiri Pirko err = __nsim_dev_init(ns); 227*8fb4bc6fSJiri Pirko rtnl_lock(); 228*8fb4bc6fSJiri Pirko dev_put(ns->netdev); 229*8fb4bc6fSJiri Pirko return err; 230*8fb4bc6fSJiri Pirko } 231*8fb4bc6fSJiri Pirko 232*8fb4bc6fSJiri Pirko void nsim_dev_exit(struct netdevsim *ns) 233*8fb4bc6fSJiri Pirko { 234*8fb4bc6fSJiri Pirko struct devlink *devlink = ns->devlink; 235*8fb4bc6fSJiri Pirko struct nsim_dev *nsim_dev = devlink_priv(devlink); 236*8fb4bc6fSJiri Pirko 237*8fb4bc6fSJiri Pirko devlink_unregister(devlink); 238*8fb4bc6fSJiri Pirko devlink_resources_unregister(devlink, NULL); 239*8fb4bc6fSJiri Pirko nsim_fib_destroy(nsim_dev->fib_data); 240*8fb4bc6fSJiri Pirko devlink_free(devlink); 241*8fb4bc6fSJiri Pirko } 242