Commit 95f510d0 authored by Vladimir Oltean's avatar Vladimir Oltean Committed by Paolo Abeni
Browse files

net: dsa: allow the DSA master to be seen and changed through rtnetlink



Some DSA switches have multiple CPU ports, which can be used to improve
CPU termination throughput, but DSA, through dsa_tree_setup_cpu_ports(),
sets up only the first one, leading to suboptimal use of hardware.

The desire is to not change the default configuration but to permit the
user to create a dynamic mapping between individual user ports and the
CPU port that they are served by, configurable through rtnetlink. It is
also intended to permit load balancing between CPU ports, and in that
case, the foreseen model is for the DSA master to be a bonding interface
whose lowers are the physical DSA masters.

To that end, we create a struct rtnl_link_ops for DSA user ports with
the "dsa" kind. We expose the IFLA_DSA_MASTER link attribute that
contains the ifindex of the newly desired DSA master.

Signed-off-by: default avatarVladimir Oltean <vladimir.oltean@nxp.com>
Signed-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
parent 8f6a19c0
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -559,6 +559,10 @@ static inline bool dsa_is_user_port(struct dsa_switch *ds, int p)
	list_for_each_entry((_dp), &(_dst)->ports, list) \
		if (dsa_port_is_user((_dp)))

#define dsa_tree_for_each_user_port_continue_reverse(_dp, _dst) \
	list_for_each_entry_continue_reverse((_dp), &(_dst)->ports, list) \
		if (dsa_port_is_user((_dp)))

#define dsa_tree_for_each_cpu_port(_dp, _dst) \
	list_for_each_entry((_dp), &(_dst)->ports, list) \
		if (dsa_port_is_cpu((_dp)))
@@ -830,6 +834,10 @@ struct dsa_switch_ops {
	int	(*connect_tag_protocol)(struct dsa_switch *ds,
					enum dsa_tag_protocol proto);

	int	(*port_change_master)(struct dsa_switch *ds, int port,
				      struct net_device *master,
				      struct netlink_ext_ack *extack);

	/* Optional switch-wide initialization and destruction methods */
	int	(*setup)(struct dsa_switch *ds);
	void	(*teardown)(struct dsa_switch *ds);
+10 −0
Original line number Diff line number Diff line
@@ -1375,4 +1375,14 @@ enum {

#define IFLA_MCTP_MAX (__IFLA_MCTP_MAX - 1)

/* DSA section */

enum {
	IFLA_DSA_UNSPEC,
	IFLA_DSA_MASTER,
	__IFLA_DSA_MAX,
};

#define IFLA_DSA_MAX	(__IFLA_DSA_MAX - 1)

#endif /* _UAPI_LINUX_IF_LINK_H */
+9 −1
Original line number Diff line number Diff line
# SPDX-License-Identifier: GPL-2.0
# the core
obj-$(CONFIG_NET_DSA) += dsa_core.o
dsa_core-y += dsa.o dsa2.o master.o port.o slave.o switch.o tag_8021q.o
dsa_core-y += \
	dsa.o \
	dsa2.o \
	master.o \
	netlink.o \
	port.o \
	slave.o \
	switch.o \
	tag_8021q.o

# tagging formats
obj-$(CONFIG_NET_DSA_TAG_AR9331) += tag_ar9331.o
+9 −0
Original line number Diff line number Diff line
@@ -536,8 +536,16 @@ static int __init dsa_init_module(void)
	dsa_tag_driver_register(&DSA_TAG_DRIVER_NAME(none_ops),
				THIS_MODULE);

	rc = rtnl_link_register(&dsa_link_ops);
	if (rc)
		goto netlink_register_fail;

	return 0;

netlink_register_fail:
	dsa_tag_driver_unregister(&DSA_TAG_DRIVER_NAME(none_ops));
	dsa_slave_unregister_notifier();
	dev_remove_pack(&dsa_pack_type);
register_notifier_fail:
	destroy_workqueue(dsa_owq);

@@ -547,6 +555,7 @@ module_init(dsa_init_module);

static void __exit dsa_cleanup_module(void)
{
	rtnl_link_unregister(&dsa_link_ops);
	dsa_tag_driver_unregister(&DSA_TAG_DRIVER_NAME(none_ops));

	dsa_slave_unregister_notifier();
+14 −0
Original line number Diff line number Diff line
@@ -387,6 +387,20 @@ static struct dsa_port *dsa_tree_find_first_cpu(struct dsa_switch_tree *dst)
	return NULL;
}

struct net_device *dsa_tree_find_first_master(struct dsa_switch_tree *dst)
{
	struct device_node *ethernet;
	struct net_device *master;
	struct dsa_port *cpu_dp;

	cpu_dp = dsa_tree_find_first_cpu(dst);
	ethernet = of_parse_phandle(cpu_dp->dn, "ethernet", 0);
	master = of_find_net_device_by_node(ethernet);
	of_node_put(ethernet);

	return master;
}

/* Assign the default CPU port (the first one in the tree) to all ports of the
 * fabric which don't already have one as part of their own switch.
 */
Loading