Beispiel #1
0
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,
					&params);
	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, &params);
	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, &params);
	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,
					&params);
	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, &params);
	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, &params);
	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;
}
Beispiel #2
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;
}