at v4.17 6.9 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{ 152 enum nsim_resource_id res_ids[] = { 153 NSIM_RESOURCE_IPV4_FIB, NSIM_RESOURCE_IPV4_FIB_RULES, 154 NSIM_RESOURCE_IPV6_FIB, NSIM_RESOURCE_IPV6_FIB_RULES 155 }; 156 struct net *net = nsim_devlink_net(devlink); 157 int i; 158 159 for (i = 0; i < ARRAY_SIZE(res_ids); ++i) { 160 int err; 161 u64 val; 162 163 err = devlink_resource_size_get(devlink, res_ids[i], &val); 164 if (!err) { 165 err = nsim_fib_set_max(net, res_ids[i], val); 166 if (err) 167 return err; 168 } 169 } 170 171 return 0; 172} 173 174static void nsim_devlink_net_reset(struct net *net) 175{ 176 enum nsim_resource_id res_ids[] = { 177 NSIM_RESOURCE_IPV4_FIB, NSIM_RESOURCE_IPV4_FIB_RULES, 178 NSIM_RESOURCE_IPV6_FIB, NSIM_RESOURCE_IPV6_FIB_RULES 179 }; 180 int i; 181 182 for (i = 0; i < ARRAY_SIZE(res_ids); ++i) { 183 if (nsim_fib_set_max(net, res_ids[i], (u64)-1)) { 184 pr_err("Failed to reset limit for resource %u\n", 185 res_ids[i]); 186 } 187 } 188} 189 190static const struct devlink_ops nsim_devlink_ops = { 191 .reload = nsim_devlink_reload, 192}; 193 194/* once devlink / namespace issues are sorted out 195 * this needs to be net in which a devlink instance 196 * is to be created. e.g., dev_net(ns->netdev) 197 */ 198static struct net *nsim_to_net(struct netdevsim *ns) 199{ 200 return &init_net; 201} 202 203void nsim_devlink_teardown(struct netdevsim *ns) 204{ 205 if (ns->devlink) { 206 struct net *net = nsim_to_net(ns); 207 bool *reg_devlink = net_generic(net, nsim_devlink_id); 208 209 devlink_unregister(ns->devlink); 210 devlink_free(ns->devlink); 211 ns->devlink = NULL; 212 213 nsim_devlink_net_reset(net); 214 *reg_devlink = true; 215 } 216} 217 218int nsim_devlink_setup(struct netdevsim *ns) 219{ 220 struct net *net = nsim_to_net(ns); 221 bool *reg_devlink = net_generic(net, nsim_devlink_id); 222 struct devlink *devlink; 223 int err; 224 225 /* only one device per namespace controls devlink */ 226 if (!*reg_devlink) { 227 ns->devlink = NULL; 228 return 0; 229 } 230 231 devlink = devlink_alloc(&nsim_devlink_ops, 0); 232 if (!devlink) 233 return -ENOMEM; 234 235 err = devlink_register(devlink, &ns->dev); 236 if (err) 237 goto err_devlink_free; 238 239 err = devlink_resources_register(devlink); 240 if (err) 241 goto err_dl_unregister; 242 243 ns->devlink = devlink; 244 245 *reg_devlink = false; 246 247 return 0; 248 249err_dl_unregister: 250 devlink_unregister(devlink); 251err_devlink_free: 252 devlink_free(devlink); 253 254 return err; 255} 256 257/* Initialize per network namespace state */ 258static int __net_init nsim_devlink_netns_init(struct net *net) 259{ 260 bool *reg_devlink = net_generic(net, nsim_devlink_id); 261 262 *reg_devlink = true; 263 264 return 0; 265} 266 267static struct pernet_operations nsim_devlink_net_ops = { 268 .init = nsim_devlink_netns_init, 269 .id = &nsim_devlink_id, 270 .size = sizeof(bool), 271}; 272 273void nsim_devlink_exit(void) 274{ 275 unregister_pernet_subsys(&nsim_devlink_net_ops); 276 nsim_fib_exit(); 277} 278 279int nsim_devlink_init(void) 280{ 281 int err; 282 283 err = nsim_fib_init(); 284 if (err) 285 goto err_out; 286 287 err = register_pernet_subsys(&nsim_devlink_net_ops); 288 if (err) 289 nsim_fib_exit(); 290 291err_out: 292 return err; 293}