at v4.19 7.0 kB view raw
1/* 2 * Copyright (c) 2018 Cumulus Networks. All rights reserved. 3 * Copyright (c) 2018 David Ahern <dsa@cumulusnetworks.com> 4 * 5 * This software is licensed under the GNU General License Version 2, 6 * June 1991 as shown in the file COPYING in the top-level directory of this 7 * source tree. 8 * 9 * THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" 10 * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, 11 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 12 * FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE 13 * OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME 14 * THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 15 */ 16 17#include <linux/device.h> 18#include <net/devlink.h> 19#include <net/netns/generic.h> 20 21#include "netdevsim.h" 22 23static unsigned int nsim_devlink_id; 24 25/* place holder until devlink and namespaces is sorted out */ 26static struct net *nsim_devlink_net(struct devlink *devlink) 27{ 28 return &init_net; 29} 30 31/* IPv4 32 */ 33static u64 nsim_ipv4_fib_resource_occ_get(void *priv) 34{ 35 struct net *net = priv; 36 37 return nsim_fib_get_val(net, NSIM_RESOURCE_IPV4_FIB, false); 38} 39 40static u64 nsim_ipv4_fib_rules_res_occ_get(void *priv) 41{ 42 struct net *net = priv; 43 44 return nsim_fib_get_val(net, NSIM_RESOURCE_IPV4_FIB_RULES, false); 45} 46 47/* IPv6 48 */ 49static u64 nsim_ipv6_fib_resource_occ_get(void *priv) 50{ 51 struct net *net = priv; 52 53 return nsim_fib_get_val(net, NSIM_RESOURCE_IPV6_FIB, false); 54} 55 56static u64 nsim_ipv6_fib_rules_res_occ_get(void *priv) 57{ 58 struct net *net = priv; 59 60 return nsim_fib_get_val(net, NSIM_RESOURCE_IPV6_FIB_RULES, false); 61} 62 63static int devlink_resources_register(struct devlink *devlink) 64{ 65 struct devlink_resource_size_params params = { 66 .size_max = (u64)-1, 67 .size_granularity = 1, 68 .unit = DEVLINK_RESOURCE_UNIT_ENTRY 69 }; 70 struct net *net = nsim_devlink_net(devlink); 71 int err; 72 u64 n; 73 74 /* Resources for IPv4 */ 75 err = devlink_resource_register(devlink, "IPv4", (u64)-1, 76 NSIM_RESOURCE_IPV4, 77 DEVLINK_RESOURCE_ID_PARENT_TOP, 78 &params); 79 if (err) { 80 pr_err("Failed to register IPv4 top resource\n"); 81 goto out; 82 } 83 84 n = nsim_fib_get_val(net, NSIM_RESOURCE_IPV4_FIB, true); 85 err = devlink_resource_register(devlink, "fib", n, 86 NSIM_RESOURCE_IPV4_FIB, 87 NSIM_RESOURCE_IPV4, &params); 88 if (err) { 89 pr_err("Failed to register IPv4 FIB resource\n"); 90 return err; 91 } 92 93 n = nsim_fib_get_val(net, NSIM_RESOURCE_IPV4_FIB_RULES, true); 94 err = devlink_resource_register(devlink, "fib-rules", n, 95 NSIM_RESOURCE_IPV4_FIB_RULES, 96 NSIM_RESOURCE_IPV4, &params); 97 if (err) { 98 pr_err("Failed to register IPv4 FIB rules resource\n"); 99 return err; 100 } 101 102 /* Resources for IPv6 */ 103 err = devlink_resource_register(devlink, "IPv6", (u64)-1, 104 NSIM_RESOURCE_IPV6, 105 DEVLINK_RESOURCE_ID_PARENT_TOP, 106 &params); 107 if (err) { 108 pr_err("Failed to register IPv6 top resource\n"); 109 goto out; 110 } 111 112 n = nsim_fib_get_val(net, NSIM_RESOURCE_IPV6_FIB, true); 113 err = devlink_resource_register(devlink, "fib", n, 114 NSIM_RESOURCE_IPV6_FIB, 115 NSIM_RESOURCE_IPV6, &params); 116 if (err) { 117 pr_err("Failed to register IPv6 FIB resource\n"); 118 return err; 119 } 120 121 n = nsim_fib_get_val(net, NSIM_RESOURCE_IPV6_FIB_RULES, true); 122 err = devlink_resource_register(devlink, "fib-rules", n, 123 NSIM_RESOURCE_IPV6_FIB_RULES, 124 NSIM_RESOURCE_IPV6, &params); 125 if (err) { 126 pr_err("Failed to register IPv6 FIB rules resource\n"); 127 return err; 128 } 129 130 devlink_resource_occ_get_register(devlink, 131 NSIM_RESOURCE_IPV4_FIB, 132 nsim_ipv4_fib_resource_occ_get, 133 net); 134 devlink_resource_occ_get_register(devlink, 135 NSIM_RESOURCE_IPV4_FIB_RULES, 136 nsim_ipv4_fib_rules_res_occ_get, 137 net); 138 devlink_resource_occ_get_register(devlink, 139 NSIM_RESOURCE_IPV6_FIB, 140 nsim_ipv6_fib_resource_occ_get, 141 net); 142 devlink_resource_occ_get_register(devlink, 143 NSIM_RESOURCE_IPV6_FIB_RULES, 144 nsim_ipv6_fib_rules_res_occ_get, 145 net); 146out: 147 return err; 148} 149 150static int nsim_devlink_reload(struct devlink *devlink, 151 struct netlink_ext_ack *extack) 152{ 153 enum nsim_resource_id res_ids[] = { 154 NSIM_RESOURCE_IPV4_FIB, NSIM_RESOURCE_IPV4_FIB_RULES, 155 NSIM_RESOURCE_IPV6_FIB, NSIM_RESOURCE_IPV6_FIB_RULES 156 }; 157 struct net *net = nsim_devlink_net(devlink); 158 int i; 159 160 for (i = 0; i < ARRAY_SIZE(res_ids); ++i) { 161 int err; 162 u64 val; 163 164 err = devlink_resource_size_get(devlink, res_ids[i], &val); 165 if (!err) { 166 err = nsim_fib_set_max(net, res_ids[i], val, extack); 167 if (err) 168 return err; 169 } 170 } 171 172 return 0; 173} 174 175static void nsim_devlink_net_reset(struct net *net) 176{ 177 enum nsim_resource_id res_ids[] = { 178 NSIM_RESOURCE_IPV4_FIB, NSIM_RESOURCE_IPV4_FIB_RULES, 179 NSIM_RESOURCE_IPV6_FIB, NSIM_RESOURCE_IPV6_FIB_RULES 180 }; 181 int i; 182 183 for (i = 0; i < ARRAY_SIZE(res_ids); ++i) { 184 if (nsim_fib_set_max(net, res_ids[i], (u64)-1, NULL)) { 185 pr_err("Failed to reset limit for resource %u\n", 186 res_ids[i]); 187 } 188 } 189} 190 191static const struct devlink_ops nsim_devlink_ops = { 192 .reload = nsim_devlink_reload, 193}; 194 195/* once devlink / namespace issues are sorted out 196 * this needs to be net in which a devlink instance 197 * is to be created. e.g., dev_net(ns->netdev) 198 */ 199static struct net *nsim_to_net(struct netdevsim *ns) 200{ 201 return &init_net; 202} 203 204void nsim_devlink_teardown(struct netdevsim *ns) 205{ 206 if (ns->devlink) { 207 struct net *net = nsim_to_net(ns); 208 bool *reg_devlink = net_generic(net, nsim_devlink_id); 209 210 devlink_resources_unregister(ns->devlink, NULL); 211 devlink_unregister(ns->devlink); 212 devlink_free(ns->devlink); 213 ns->devlink = NULL; 214 215 nsim_devlink_net_reset(net); 216 *reg_devlink = true; 217 } 218} 219 220int nsim_devlink_setup(struct netdevsim *ns) 221{ 222 struct net *net = nsim_to_net(ns); 223 bool *reg_devlink = net_generic(net, nsim_devlink_id); 224 struct devlink *devlink; 225 int err; 226 227 /* only one device per namespace controls devlink */ 228 if (!*reg_devlink) { 229 ns->devlink = NULL; 230 return 0; 231 } 232 233 devlink = devlink_alloc(&nsim_devlink_ops, 0); 234 if (!devlink) 235 return -ENOMEM; 236 237 err = devlink_register(devlink, &ns->dev); 238 if (err) 239 goto err_devlink_free; 240 241 err = devlink_resources_register(devlink); 242 if (err) 243 goto err_dl_unregister; 244 245 ns->devlink = devlink; 246 247 *reg_devlink = false; 248 249 return 0; 250 251err_dl_unregister: 252 devlink_unregister(devlink); 253err_devlink_free: 254 devlink_free(devlink); 255 256 return err; 257} 258 259/* Initialize per network namespace state */ 260static int __net_init nsim_devlink_netns_init(struct net *net) 261{ 262 bool *reg_devlink = net_generic(net, nsim_devlink_id); 263 264 *reg_devlink = true; 265 266 return 0; 267} 268 269static struct pernet_operations nsim_devlink_net_ops = { 270 .init = nsim_devlink_netns_init, 271 .id = &nsim_devlink_id, 272 .size = sizeof(bool), 273}; 274 275void nsim_devlink_exit(void) 276{ 277 unregister_pernet_subsys(&nsim_devlink_net_ops); 278 nsim_fib_exit(); 279} 280 281int nsim_devlink_init(void) 282{ 283 int err; 284 285 err = nsim_fib_init(); 286 if (err) 287 goto err_out; 288 289 err = register_pernet_subsys(&nsim_devlink_net_ops); 290 if (err) 291 nsim_fib_exit(); 292 293err_out: 294 return err; 295}