1 /* 2 * Copyright (c) 2018 Cumulus Networks. All rights reserved. 3 * Copyright (c) 2018 David Ahern <dsa@cumulusnetworks.com> 4 * Copyright (c) 2019 Mellanox Technologies. All rights reserved. 5 * 6 * This software is licensed under the GNU General License Version 2, 7 * June 1991 as shown in the file COPYING in the top-level directory of this 8 * source tree. 9 * 10 * THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" 11 * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, 12 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 13 * FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE 14 * OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME 15 * THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16 */ 17 18 #include <linux/debugfs.h> 19 #include <linux/device.h> 20 #include <linux/list.h> 21 #include <linux/mutex.h> 22 #include <linux/random.h> 23 #include <linux/rtnetlink.h> 24 #include <net/devlink.h> 25 26 #include "netdevsim.h" 27 28 static struct dentry *nsim_dev_ddir; 29 30 static int nsim_dev_debugfs_init(struct nsim_dev *nsim_dev) 31 { 32 char dev_ddir_name[16]; 33 34 sprintf(dev_ddir_name, DRV_NAME "%u", nsim_dev->nsim_bus_dev->dev.id); 35 nsim_dev->ddir = debugfs_create_dir(dev_ddir_name, nsim_dev_ddir); 36 if (IS_ERR_OR_NULL(nsim_dev->ddir)) 37 return PTR_ERR_OR_ZERO(nsim_dev->ddir) ?: -EINVAL; 38 nsim_dev->ports_ddir = debugfs_create_dir("ports", nsim_dev->ddir); 39 if (IS_ERR_OR_NULL(nsim_dev->ports_ddir)) 40 return PTR_ERR_OR_ZERO(nsim_dev->ports_ddir) ?: -EINVAL; 41 debugfs_create_bool("fw_update_status", 0600, nsim_dev->ddir, 42 &nsim_dev->fw_update_status); 43 debugfs_create_u32("max_macs", 0600, nsim_dev->ddir, 44 &nsim_dev->max_macs); 45 debugfs_create_bool("test1", 0600, nsim_dev->ddir, 46 &nsim_dev->test1); 47 return 0; 48 } 49 50 static void nsim_dev_debugfs_exit(struct nsim_dev *nsim_dev) 51 { 52 debugfs_remove_recursive(nsim_dev->ports_ddir); 53 debugfs_remove_recursive(nsim_dev->ddir); 54 } 55 56 static int nsim_dev_port_debugfs_init(struct nsim_dev *nsim_dev, 57 struct nsim_dev_port *nsim_dev_port) 58 { 59 char port_ddir_name[16]; 60 char dev_link_name[32]; 61 62 sprintf(port_ddir_name, "%u", nsim_dev_port->port_index); 63 nsim_dev_port->ddir = debugfs_create_dir(port_ddir_name, 64 nsim_dev->ports_ddir); 65 if (IS_ERR_OR_NULL(nsim_dev_port->ddir)) 66 return -ENOMEM; 67 68 sprintf(dev_link_name, "../../../" DRV_NAME "%u", 69 nsim_dev->nsim_bus_dev->dev.id); 70 debugfs_create_symlink("dev", nsim_dev_port->ddir, dev_link_name); 71 72 return 0; 73 } 74 75 static void nsim_dev_port_debugfs_exit(struct nsim_dev_port *nsim_dev_port) 76 { 77 debugfs_remove_recursive(nsim_dev_port->ddir); 78 } 79 80 static u64 nsim_dev_ipv4_fib_resource_occ_get(void *priv) 81 { 82 struct nsim_dev *nsim_dev = priv; 83 84 return nsim_fib_get_val(nsim_dev->fib_data, 85 NSIM_RESOURCE_IPV4_FIB, false); 86 } 87 88 static u64 nsim_dev_ipv4_fib_rules_res_occ_get(void *priv) 89 { 90 struct nsim_dev *nsim_dev = priv; 91 92 return nsim_fib_get_val(nsim_dev->fib_data, 93 NSIM_RESOURCE_IPV4_FIB_RULES, false); 94 } 95 96 static u64 nsim_dev_ipv6_fib_resource_occ_get(void *priv) 97 { 98 struct nsim_dev *nsim_dev = priv; 99 100 return nsim_fib_get_val(nsim_dev->fib_data, 101 NSIM_RESOURCE_IPV6_FIB, false); 102 } 103 104 static u64 nsim_dev_ipv6_fib_rules_res_occ_get(void *priv) 105 { 106 struct nsim_dev *nsim_dev = priv; 107 108 return nsim_fib_get_val(nsim_dev->fib_data, 109 NSIM_RESOURCE_IPV6_FIB_RULES, false); 110 } 111 112 static int nsim_dev_resources_register(struct devlink *devlink) 113 { 114 struct nsim_dev *nsim_dev = devlink_priv(devlink); 115 struct devlink_resource_size_params params = { 116 .size_max = (u64)-1, 117 .size_granularity = 1, 118 .unit = DEVLINK_RESOURCE_UNIT_ENTRY 119 }; 120 int err; 121 u64 n; 122 123 /* Resources for IPv4 */ 124 err = devlink_resource_register(devlink, "IPv4", (u64)-1, 125 NSIM_RESOURCE_IPV4, 126 DEVLINK_RESOURCE_ID_PARENT_TOP, 127 ¶ms); 128 if (err) { 129 pr_err("Failed to register IPv4 top resource\n"); 130 goto out; 131 } 132 133 n = nsim_fib_get_val(nsim_dev->fib_data, 134 NSIM_RESOURCE_IPV4_FIB, true); 135 err = devlink_resource_register(devlink, "fib", n, 136 NSIM_RESOURCE_IPV4_FIB, 137 NSIM_RESOURCE_IPV4, ¶ms); 138 if (err) { 139 pr_err("Failed to register IPv4 FIB resource\n"); 140 return err; 141 } 142 143 n = nsim_fib_get_val(nsim_dev->fib_data, 144 NSIM_RESOURCE_IPV4_FIB_RULES, true); 145 err = devlink_resource_register(devlink, "fib-rules", n, 146 NSIM_RESOURCE_IPV4_FIB_RULES, 147 NSIM_RESOURCE_IPV4, ¶ms); 148 if (err) { 149 pr_err("Failed to register IPv4 FIB rules resource\n"); 150 return err; 151 } 152 153 /* Resources for IPv6 */ 154 err = devlink_resource_register(devlink, "IPv6", (u64)-1, 155 NSIM_RESOURCE_IPV6, 156 DEVLINK_RESOURCE_ID_PARENT_TOP, 157 ¶ms); 158 if (err) { 159 pr_err("Failed to register IPv6 top resource\n"); 160 goto out; 161 } 162 163 n = nsim_fib_get_val(nsim_dev->fib_data, 164 NSIM_RESOURCE_IPV6_FIB, true); 165 err = devlink_resource_register(devlink, "fib", n, 166 NSIM_RESOURCE_IPV6_FIB, 167 NSIM_RESOURCE_IPV6, ¶ms); 168 if (err) { 169 pr_err("Failed to register IPv6 FIB resource\n"); 170 return err; 171 } 172 173 n = nsim_fib_get_val(nsim_dev->fib_data, 174 NSIM_RESOURCE_IPV6_FIB_RULES, true); 175 err = devlink_resource_register(devlink, "fib-rules", n, 176 NSIM_RESOURCE_IPV6_FIB_RULES, 177 NSIM_RESOURCE_IPV6, ¶ms); 178 if (err) { 179 pr_err("Failed to register IPv6 FIB rules resource\n"); 180 return err; 181 } 182 183 devlink_resource_occ_get_register(devlink, 184 NSIM_RESOURCE_IPV4_FIB, 185 nsim_dev_ipv4_fib_resource_occ_get, 186 nsim_dev); 187 devlink_resource_occ_get_register(devlink, 188 NSIM_RESOURCE_IPV4_FIB_RULES, 189 nsim_dev_ipv4_fib_rules_res_occ_get, 190 nsim_dev); 191 devlink_resource_occ_get_register(devlink, 192 NSIM_RESOURCE_IPV6_FIB, 193 nsim_dev_ipv6_fib_resource_occ_get, 194 nsim_dev); 195 devlink_resource_occ_get_register(devlink, 196 NSIM_RESOURCE_IPV6_FIB_RULES, 197 nsim_dev_ipv6_fib_rules_res_occ_get, 198 nsim_dev); 199 out: 200 return err; 201 } 202 203 enum nsim_devlink_param_id { 204 NSIM_DEVLINK_PARAM_ID_BASE = DEVLINK_PARAM_GENERIC_ID_MAX, 205 NSIM_DEVLINK_PARAM_ID_TEST1, 206 }; 207 208 static const struct devlink_param nsim_devlink_params[] = { 209 DEVLINK_PARAM_GENERIC(MAX_MACS, 210 BIT(DEVLINK_PARAM_CMODE_DRIVERINIT), 211 NULL, NULL, NULL), 212 DEVLINK_PARAM_DRIVER(NSIM_DEVLINK_PARAM_ID_TEST1, 213 "test1", DEVLINK_PARAM_TYPE_BOOL, 214 BIT(DEVLINK_PARAM_CMODE_DRIVERINIT), 215 NULL, NULL, NULL), 216 }; 217 218 static void nsim_devlink_set_params_init_values(struct nsim_dev *nsim_dev, 219 struct devlink *devlink) 220 { 221 union devlink_param_value value; 222 223 value.vu32 = nsim_dev->max_macs; 224 devlink_param_driverinit_value_set(devlink, 225 DEVLINK_PARAM_GENERIC_ID_MAX_MACS, 226 value); 227 value.vbool = nsim_dev->test1; 228 devlink_param_driverinit_value_set(devlink, 229 NSIM_DEVLINK_PARAM_ID_TEST1, 230 value); 231 } 232 233 static void nsim_devlink_param_load_driverinit_values(struct devlink *devlink) 234 { 235 struct nsim_dev *nsim_dev = devlink_priv(devlink); 236 union devlink_param_value saved_value; 237 int err; 238 239 err = devlink_param_driverinit_value_get(devlink, 240 DEVLINK_PARAM_GENERIC_ID_MAX_MACS, 241 &saved_value); 242 if (!err) 243 nsim_dev->max_macs = saved_value.vu32; 244 err = devlink_param_driverinit_value_get(devlink, 245 NSIM_DEVLINK_PARAM_ID_TEST1, 246 &saved_value); 247 if (!err) 248 nsim_dev->test1 = saved_value.vbool; 249 } 250 251 static int nsim_dev_reload(struct devlink *devlink, 252 struct netlink_ext_ack *extack) 253 { 254 struct nsim_dev *nsim_dev = devlink_priv(devlink); 255 enum nsim_resource_id res_ids[] = { 256 NSIM_RESOURCE_IPV4_FIB, NSIM_RESOURCE_IPV4_FIB_RULES, 257 NSIM_RESOURCE_IPV6_FIB, NSIM_RESOURCE_IPV6_FIB_RULES 258 }; 259 int i; 260 261 for (i = 0; i < ARRAY_SIZE(res_ids); ++i) { 262 int err; 263 u64 val; 264 265 err = devlink_resource_size_get(devlink, res_ids[i], &val); 266 if (!err) { 267 err = nsim_fib_set_max(nsim_dev->fib_data, 268 res_ids[i], val, extack); 269 if (err) 270 return err; 271 } 272 } 273 nsim_devlink_param_load_driverinit_values(devlink); 274 275 return 0; 276 } 277 278 #define NSIM_DEV_FLASH_SIZE 500000 279 #define NSIM_DEV_FLASH_CHUNK_SIZE 1000 280 #define NSIM_DEV_FLASH_CHUNK_TIME_MS 10 281 282 static int nsim_dev_flash_update(struct devlink *devlink, const char *file_name, 283 const char *component, 284 struct netlink_ext_ack *extack) 285 { 286 struct nsim_dev *nsim_dev = devlink_priv(devlink); 287 int i; 288 289 if (nsim_dev->fw_update_status) { 290 devlink_flash_update_begin_notify(devlink); 291 devlink_flash_update_status_notify(devlink, 292 "Preparing to flash", 293 component, 0, 0); 294 } 295 296 for (i = 0; i < NSIM_DEV_FLASH_SIZE / NSIM_DEV_FLASH_CHUNK_SIZE; i++) { 297 if (nsim_dev->fw_update_status) 298 devlink_flash_update_status_notify(devlink, "Flashing", 299 component, 300 i * NSIM_DEV_FLASH_CHUNK_SIZE, 301 NSIM_DEV_FLASH_SIZE); 302 msleep(NSIM_DEV_FLASH_CHUNK_TIME_MS); 303 } 304 305 if (nsim_dev->fw_update_status) { 306 devlink_flash_update_status_notify(devlink, "Flashing", 307 component, 308 NSIM_DEV_FLASH_SIZE, 309 NSIM_DEV_FLASH_SIZE); 310 devlink_flash_update_status_notify(devlink, "Flashing done", 311 component, 0, 0); 312 devlink_flash_update_end_notify(devlink); 313 } 314 315 return 0; 316 } 317 318 static const struct devlink_ops nsim_dev_devlink_ops = { 319 .reload = nsim_dev_reload, 320 .flash_update = nsim_dev_flash_update, 321 }; 322 323 #define NSIM_DEV_MAX_MACS_DEFAULT 32 324 #define NSIM_DEV_TEST1_DEFAULT true 325 326 static struct nsim_dev * 327 nsim_dev_create(struct nsim_bus_dev *nsim_bus_dev, unsigned int port_count) 328 { 329 struct nsim_dev *nsim_dev; 330 struct devlink *devlink; 331 int err; 332 333 devlink = devlink_alloc(&nsim_dev_devlink_ops, sizeof(*nsim_dev)); 334 if (!devlink) 335 return ERR_PTR(-ENOMEM); 336 nsim_dev = devlink_priv(devlink); 337 nsim_dev->nsim_bus_dev = nsim_bus_dev; 338 nsim_dev->switch_id.id_len = sizeof(nsim_dev->switch_id.id); 339 get_random_bytes(nsim_dev->switch_id.id, nsim_dev->switch_id.id_len); 340 INIT_LIST_HEAD(&nsim_dev->port_list); 341 mutex_init(&nsim_dev->port_list_lock); 342 nsim_dev->fw_update_status = true; 343 nsim_dev->max_macs = NSIM_DEV_MAX_MACS_DEFAULT; 344 nsim_dev->test1 = NSIM_DEV_TEST1_DEFAULT; 345 346 nsim_dev->fib_data = nsim_fib_create(); 347 if (IS_ERR(nsim_dev->fib_data)) { 348 err = PTR_ERR(nsim_dev->fib_data); 349 goto err_devlink_free; 350 } 351 352 err = nsim_dev_resources_register(devlink); 353 if (err) 354 goto err_fib_destroy; 355 356 err = devlink_register(devlink, &nsim_bus_dev->dev); 357 if (err) 358 goto err_resources_unregister; 359 360 err = devlink_params_register(devlink, nsim_devlink_params, 361 ARRAY_SIZE(nsim_devlink_params)); 362 if (err) 363 goto err_dl_unregister; 364 nsim_devlink_set_params_init_values(nsim_dev, devlink); 365 366 err = nsim_dev_debugfs_init(nsim_dev); 367 if (err) 368 goto err_params_unregister; 369 370 err = nsim_bpf_dev_init(nsim_dev); 371 if (err) 372 goto err_debugfs_exit; 373 374 devlink_params_publish(devlink); 375 return nsim_dev; 376 377 err_debugfs_exit: 378 nsim_dev_debugfs_exit(nsim_dev); 379 err_params_unregister: 380 devlink_params_unregister(devlink, nsim_devlink_params, 381 ARRAY_SIZE(nsim_devlink_params)); 382 err_dl_unregister: 383 devlink_unregister(devlink); 384 err_resources_unregister: 385 devlink_resources_unregister(devlink, NULL); 386 err_fib_destroy: 387 nsim_fib_destroy(nsim_dev->fib_data); 388 err_devlink_free: 389 devlink_free(devlink); 390 return ERR_PTR(err); 391 } 392 393 static void nsim_dev_destroy(struct nsim_dev *nsim_dev) 394 { 395 struct devlink *devlink = priv_to_devlink(nsim_dev); 396 397 nsim_bpf_dev_exit(nsim_dev); 398 nsim_dev_debugfs_exit(nsim_dev); 399 devlink_params_unregister(devlink, nsim_devlink_params, 400 ARRAY_SIZE(nsim_devlink_params)); 401 devlink_unregister(devlink); 402 devlink_resources_unregister(devlink, NULL); 403 nsim_fib_destroy(nsim_dev->fib_data); 404 mutex_destroy(&nsim_dev->port_list_lock); 405 devlink_free(devlink); 406 } 407 408 static int __nsim_dev_port_add(struct nsim_dev *nsim_dev, 409 unsigned int port_index) 410 { 411 struct nsim_dev_port *nsim_dev_port; 412 struct devlink_port *devlink_port; 413 int err; 414 415 nsim_dev_port = kzalloc(sizeof(*nsim_dev_port), GFP_KERNEL); 416 if (!nsim_dev_port) 417 return -ENOMEM; 418 nsim_dev_port->port_index = port_index; 419 420 devlink_port = &nsim_dev_port->devlink_port; 421 devlink_port_attrs_set(devlink_port, DEVLINK_PORT_FLAVOUR_PHYSICAL, 422 port_index + 1, 0, 0, 423 nsim_dev->switch_id.id, 424 nsim_dev->switch_id.id_len); 425 err = devlink_port_register(priv_to_devlink(nsim_dev), devlink_port, 426 port_index); 427 if (err) 428 goto err_port_free; 429 430 err = nsim_dev_port_debugfs_init(nsim_dev, nsim_dev_port); 431 if (err) 432 goto err_dl_port_unregister; 433 434 nsim_dev_port->ns = nsim_create(nsim_dev, nsim_dev_port); 435 if (IS_ERR(nsim_dev_port->ns)) { 436 err = PTR_ERR(nsim_dev_port->ns); 437 goto err_port_debugfs_exit; 438 } 439 440 devlink_port_type_eth_set(devlink_port, nsim_dev_port->ns->netdev); 441 list_add(&nsim_dev_port->list, &nsim_dev->port_list); 442 443 return 0; 444 445 err_port_debugfs_exit: 446 nsim_dev_port_debugfs_exit(nsim_dev_port); 447 err_dl_port_unregister: 448 devlink_port_unregister(devlink_port); 449 err_port_free: 450 kfree(nsim_dev_port); 451 return err; 452 } 453 454 static void __nsim_dev_port_del(struct nsim_dev_port *nsim_dev_port) 455 { 456 struct devlink_port *devlink_port = &nsim_dev_port->devlink_port; 457 458 list_del(&nsim_dev_port->list); 459 devlink_port_type_clear(devlink_port); 460 nsim_destroy(nsim_dev_port->ns); 461 nsim_dev_port_debugfs_exit(nsim_dev_port); 462 devlink_port_unregister(devlink_port); 463 kfree(nsim_dev_port); 464 } 465 466 static void nsim_dev_port_del_all(struct nsim_dev *nsim_dev) 467 { 468 struct nsim_dev_port *nsim_dev_port, *tmp; 469 470 list_for_each_entry_safe(nsim_dev_port, tmp, 471 &nsim_dev->port_list, list) 472 __nsim_dev_port_del(nsim_dev_port); 473 } 474 475 int nsim_dev_probe(struct nsim_bus_dev *nsim_bus_dev) 476 { 477 struct nsim_dev *nsim_dev; 478 int i; 479 int err; 480 481 nsim_dev = nsim_dev_create(nsim_bus_dev, nsim_bus_dev->port_count); 482 if (IS_ERR(nsim_dev)) 483 return PTR_ERR(nsim_dev); 484 dev_set_drvdata(&nsim_bus_dev->dev, nsim_dev); 485 486 for (i = 0; i < nsim_bus_dev->port_count; i++) { 487 err = __nsim_dev_port_add(nsim_dev, i); 488 if (err) 489 goto err_port_del_all; 490 } 491 return 0; 492 493 err_port_del_all: 494 nsim_dev_port_del_all(nsim_dev); 495 nsim_dev_destroy(nsim_dev); 496 return err; 497 } 498 499 void nsim_dev_remove(struct nsim_bus_dev *nsim_bus_dev) 500 { 501 struct nsim_dev *nsim_dev = dev_get_drvdata(&nsim_bus_dev->dev); 502 503 nsim_dev_port_del_all(nsim_dev); 504 nsim_dev_destroy(nsim_dev); 505 } 506 507 static struct nsim_dev_port * 508 __nsim_dev_port_lookup(struct nsim_dev *nsim_dev, unsigned int port_index) 509 { 510 struct nsim_dev_port *nsim_dev_port; 511 512 list_for_each_entry(nsim_dev_port, &nsim_dev->port_list, list) 513 if (nsim_dev_port->port_index == port_index) 514 return nsim_dev_port; 515 return NULL; 516 } 517 518 int nsim_dev_port_add(struct nsim_bus_dev *nsim_bus_dev, 519 unsigned int port_index) 520 { 521 struct nsim_dev *nsim_dev = dev_get_drvdata(&nsim_bus_dev->dev); 522 int err; 523 524 mutex_lock(&nsim_dev->port_list_lock); 525 if (__nsim_dev_port_lookup(nsim_dev, port_index)) 526 err = -EEXIST; 527 else 528 err = __nsim_dev_port_add(nsim_dev, port_index); 529 mutex_unlock(&nsim_dev->port_list_lock); 530 return err; 531 } 532 533 int nsim_dev_port_del(struct nsim_bus_dev *nsim_bus_dev, 534 unsigned int port_index) 535 { 536 struct nsim_dev *nsim_dev = dev_get_drvdata(&nsim_bus_dev->dev); 537 struct nsim_dev_port *nsim_dev_port; 538 int err = 0; 539 540 mutex_lock(&nsim_dev->port_list_lock); 541 nsim_dev_port = __nsim_dev_port_lookup(nsim_dev, port_index); 542 if (!nsim_dev_port) 543 err = -ENOENT; 544 else 545 __nsim_dev_port_del(nsim_dev_port); 546 mutex_unlock(&nsim_dev->port_list_lock); 547 return err; 548 } 549 550 int nsim_dev_init(void) 551 { 552 nsim_dev_ddir = debugfs_create_dir(DRV_NAME, NULL); 553 if (IS_ERR_OR_NULL(nsim_dev_ddir)) 554 return -ENOMEM; 555 return 0; 556 } 557 558 void nsim_dev_exit(void) 559 { 560 debugfs_remove_recursive(nsim_dev_ddir); 561 } 562