static int devlink_resources_register(struct devlink *devlink) { struct devlink_resource_size_params params = { .size_max = (u64)-1, .size_granularity = 1, .unit = DEVLINK_RESOURCE_UNIT_ENTRY }; struct net *net = nsim_devlink_net(devlink); int err; u64 n; /* Resources for IPv4 */ err = devlink_resource_register(devlink, "IPv4", (u64)-1, NSIM_RESOURCE_IPV4, DEVLINK_RESOURCE_ID_PARENT_TOP, ¶ms); if (err) { pr_err("Failed to register IPv4 top resource\n"); goto out; } n = nsim_fib_get_val(net, NSIM_RESOURCE_IPV4_FIB, true); err = devlink_resource_register(devlink, "fib", n, NSIM_RESOURCE_IPV4_FIB, NSIM_RESOURCE_IPV4, ¶ms); if (err) { pr_err("Failed to register IPv4 FIB resource\n"); return err; } n = nsim_fib_get_val(net, NSIM_RESOURCE_IPV4_FIB_RULES, true); err = devlink_resource_register(devlink, "fib-rules", n, NSIM_RESOURCE_IPV4_FIB_RULES, NSIM_RESOURCE_IPV4, ¶ms); if (err) { pr_err("Failed to register IPv4 FIB rules resource\n"); return err; } /* Resources for IPv6 */ err = devlink_resource_register(devlink, "IPv6", (u64)-1, NSIM_RESOURCE_IPV6, DEVLINK_RESOURCE_ID_PARENT_TOP, ¶ms); if (err) { pr_err("Failed to register IPv6 top resource\n"); goto out; } n = nsim_fib_get_val(net, NSIM_RESOURCE_IPV6_FIB, true); err = devlink_resource_register(devlink, "fib", n, NSIM_RESOURCE_IPV6_FIB, NSIM_RESOURCE_IPV6, ¶ms); if (err) { pr_err("Failed to register IPv6 FIB resource\n"); return err; } n = nsim_fib_get_val(net, NSIM_RESOURCE_IPV6_FIB_RULES, true); err = devlink_resource_register(devlink, "fib-rules", n, NSIM_RESOURCE_IPV6_FIB_RULES, NSIM_RESOURCE_IPV6, ¶ms); if (err) { pr_err("Failed to register IPv6 FIB rules resource\n"); return err; } devlink_resource_occ_get_register(devlink, NSIM_RESOURCE_IPV4_FIB, nsim_ipv4_fib_resource_occ_get, net); devlink_resource_occ_get_register(devlink, NSIM_RESOURCE_IPV4_FIB_RULES, nsim_ipv4_fib_rules_res_occ_get, net); devlink_resource_occ_get_register(devlink, NSIM_RESOURCE_IPV6_FIB, nsim_ipv6_fib_resource_occ_get, net); devlink_resource_occ_get_register(devlink, NSIM_RESOURCE_IPV6_FIB_RULES, nsim_ipv6_fib_rules_res_occ_get, net); out: return err; } static int nsim_devlink_reload(struct devlink *devlink, struct netlink_ext_ack *extack) { enum nsim_resource_id res_ids[] = { NSIM_RESOURCE_IPV4_FIB, NSIM_RESOURCE_IPV4_FIB_RULES, NSIM_RESOURCE_IPV6_FIB, NSIM_RESOURCE_IPV6_FIB_RULES }; struct net *net = nsim_devlink_net(devlink); int i; for (i = 0; i < ARRAY_SIZE(res_ids); ++i) { int err; u64 val; err = devlink_resource_size_get(devlink, res_ids[i], &val); if (!err) { err = nsim_fib_set_max(net, res_ids[i], val, extack); if (err) return err; } } return 0; } static void nsim_devlink_net_reset(struct net *net) { enum nsim_resource_id res_ids[] = { NSIM_RESOURCE_IPV4_FIB, NSIM_RESOURCE_IPV4_FIB_RULES, NSIM_RESOURCE_IPV6_FIB, NSIM_RESOURCE_IPV6_FIB_RULES }; int i; for (i = 0; i < ARRAY_SIZE(res_ids); ++i) { if (nsim_fib_set_max(net, res_ids[i], (u64)-1, NULL)) { pr_err("Failed to reset limit for resource %u\n", res_ids[i]); } } } static const struct devlink_ops nsim_devlink_ops = { .reload = nsim_devlink_reload, }; /* once devlink / namespace issues are sorted out * this needs to be net in which a devlink instance * is to be created. e.g., dev_net(ns->netdev) */ static struct net *nsim_to_net(struct netdevsim *ns) { return &init_net; } void nsim_devlink_teardown(struct netdevsim *ns) { if (ns->devlink) { struct net *net = nsim_to_net(ns); bool *reg_devlink = net_generic(net, nsim_devlink_id); devlink_resources_unregister(ns->devlink, NULL); devlink_unregister(ns->devlink); devlink_free(ns->devlink); ns->devlink = NULL; nsim_devlink_net_reset(net); *reg_devlink = true; } } int nsim_devlink_setup(struct netdevsim *ns) { struct net *net = nsim_to_net(ns); bool *reg_devlink = net_generic(net, nsim_devlink_id); struct devlink *devlink; int err; /* only one device per namespace controls devlink */ if (!*reg_devlink) { ns->devlink = NULL; return 0; } devlink = devlink_alloc(&nsim_devlink_ops, 0); if (!devlink) return -ENOMEM; err = devlink_register(devlink, &ns->dev); if (err) goto err_devlink_free; err = devlink_resources_register(devlink); if (err) goto err_dl_unregister; ns->devlink = devlink; *reg_devlink = false; return 0; err_dl_unregister: devlink_unregister(devlink); err_devlink_free: devlink_free(devlink); return err; } /* Initialize per network namespace state */ static int __net_init nsim_devlink_netns_init(struct net *net) { bool *reg_devlink = net_generic(net, nsim_devlink_id); *reg_devlink = true; return 0; }
static int dsa_ds_apply(struct dsa_switch_tree *dst, struct dsa_switch *ds) { struct dsa_port *port; u32 index; int err; /* Initialize ds->phys_mii_mask before registering the slave MDIO bus * driver and before ops->setup() has run, since the switch drivers and * the slave MDIO bus driver rely on these values for probing PHY * devices or not */ ds->phys_mii_mask = ds->enabled_port_mask; /* Add the switch to devlink before calling setup, so that setup can * add dpipe tables */ ds->devlink = devlink_alloc(&dsa_devlink_ops, 0); if (!ds->devlink) return -ENOMEM; err = devlink_register(ds->devlink, ds->dev); if (err) return err; err = ds->ops->setup(ds); if (err < 0) return err; err = dsa_switch_register_notifier(ds); if (err) return err; if (ds->ops->set_addr) { err = ds->ops->set_addr(ds, dst->cpu_dp->netdev->dev_addr); if (err < 0) return err; } if (!ds->slave_mii_bus && ds->ops->phy_read) { ds->slave_mii_bus = devm_mdiobus_alloc(ds->dev); if (!ds->slave_mii_bus) return -ENOMEM; dsa_slave_mii_bus_init(ds); err = mdiobus_register(ds->slave_mii_bus); if (err < 0) return err; } for (index = 0; index < ds->num_ports; index++) { port = &ds->ports[index]; if (!dsa_port_is_valid(port)) continue; if (dsa_port_is_dsa(port)) { err = dsa_dsa_port_apply(port); if (err) return err; continue; } if (dsa_port_is_cpu(port)) { err = dsa_cpu_port_apply(port); if (err) return err; continue; } err = dsa_user_port_apply(port); if (err) continue; } return 0; }