Skip to content

Commit 95f510d

Browse files
vladimirolteanPaolo Abeni
authored andcommitted
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: Vladimir Oltean <[email protected]> Signed-off-by: Paolo Abeni <[email protected]>
1 parent 8f6a19c commit 95f510d

File tree

9 files changed

+372
-1
lines changed

9 files changed

+372
-1
lines changed

include/net/dsa.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -559,6 +559,10 @@ static inline bool dsa_is_user_port(struct dsa_switch *ds, int p)
559559
list_for_each_entry((_dp), &(_dst)->ports, list) \
560560
if (dsa_port_is_user((_dp)))
561561

562+
#define dsa_tree_for_each_user_port_continue_reverse(_dp, _dst) \
563+
list_for_each_entry_continue_reverse((_dp), &(_dst)->ports, list) \
564+
if (dsa_port_is_user((_dp)))
565+
562566
#define dsa_tree_for_each_cpu_port(_dp, _dst) \
563567
list_for_each_entry((_dp), &(_dst)->ports, list) \
564568
if (dsa_port_is_cpu((_dp)))
@@ -830,6 +834,10 @@ struct dsa_switch_ops {
830834
int (*connect_tag_protocol)(struct dsa_switch *ds,
831835
enum dsa_tag_protocol proto);
832836

837+
int (*port_change_master)(struct dsa_switch *ds, int port,
838+
struct net_device *master,
839+
struct netlink_ext_ack *extack);
840+
833841
/* Optional switch-wide initialization and destruction methods */
834842
int (*setup)(struct dsa_switch *ds);
835843
void (*teardown)(struct dsa_switch *ds);

include/uapi/linux/if_link.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1375,4 +1375,14 @@ enum {
13751375

13761376
#define IFLA_MCTP_MAX (__IFLA_MCTP_MAX - 1)
13771377

1378+
/* DSA section */
1379+
1380+
enum {
1381+
IFLA_DSA_UNSPEC,
1382+
IFLA_DSA_MASTER,
1383+
__IFLA_DSA_MAX,
1384+
};
1385+
1386+
#define IFLA_DSA_MAX (__IFLA_DSA_MAX - 1)
1387+
13781388
#endif /* _UAPI_LINUX_IF_LINK_H */

net/dsa/Makefile

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,15 @@
11
# SPDX-License-Identifier: GPL-2.0
22
# the core
33
obj-$(CONFIG_NET_DSA) += dsa_core.o
4-
dsa_core-y += dsa.o dsa2.o master.o port.o slave.o switch.o tag_8021q.o
4+
dsa_core-y += \
5+
dsa.o \
6+
dsa2.o \
7+
master.o \
8+
netlink.o \
9+
port.o \
10+
slave.o \
11+
switch.o \
12+
tag_8021q.o
513

614
# tagging formats
715
obj-$(CONFIG_NET_DSA_TAG_AR9331) += tag_ar9331.o

net/dsa/dsa.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -536,8 +536,16 @@ static int __init dsa_init_module(void)
536536
dsa_tag_driver_register(&DSA_TAG_DRIVER_NAME(none_ops),
537537
THIS_MODULE);
538538

539+
rc = rtnl_link_register(&dsa_link_ops);
540+
if (rc)
541+
goto netlink_register_fail;
542+
539543
return 0;
540544

545+
netlink_register_fail:
546+
dsa_tag_driver_unregister(&DSA_TAG_DRIVER_NAME(none_ops));
547+
dsa_slave_unregister_notifier();
548+
dev_remove_pack(&dsa_pack_type);
541549
register_notifier_fail:
542550
destroy_workqueue(dsa_owq);
543551

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

548556
static void __exit dsa_cleanup_module(void)
549557
{
558+
rtnl_link_unregister(&dsa_link_ops);
550559
dsa_tag_driver_unregister(&DSA_TAG_DRIVER_NAME(none_ops));
551560

552561
dsa_slave_unregister_notifier();

net/dsa/dsa2.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -387,6 +387,20 @@ static struct dsa_port *dsa_tree_find_first_cpu(struct dsa_switch_tree *dst)
387387
return NULL;
388388
}
389389

390+
struct net_device *dsa_tree_find_first_master(struct dsa_switch_tree *dst)
391+
{
392+
struct device_node *ethernet;
393+
struct net_device *master;
394+
struct dsa_port *cpu_dp;
395+
396+
cpu_dp = dsa_tree_find_first_cpu(dst);
397+
ethernet = of_parse_phandle(cpu_dp->dn, "ethernet", 0);
398+
master = of_find_net_device_by_node(ethernet);
399+
of_node_put(ethernet);
400+
401+
return master;
402+
}
403+
390404
/* Assign the default CPU port (the first one in the tree) to all ports of the
391405
* fabric which don't already have one as part of their own switch.
392406
*/

net/dsa/dsa_priv.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,9 @@ static inline struct net_device *dsa_master_find_slave(struct net_device *dev,
200200
return NULL;
201201
}
202202

203+
/* netlink.c */
204+
extern struct rtnl_link_ops dsa_link_ops __read_mostly;
205+
203206
/* port.c */
204207
void dsa_port_set_tag_protocol(struct dsa_port *cpu_dp,
205208
const struct dsa_device_ops *tag_ops);
@@ -292,6 +295,8 @@ void dsa_port_hsr_leave(struct dsa_port *dp, struct net_device *hsr);
292295
int dsa_port_tag_8021q_vlan_add(struct dsa_port *dp, u16 vid, bool broadcast);
293296
void dsa_port_tag_8021q_vlan_del(struct dsa_port *dp, u16 vid, bool broadcast);
294297
void dsa_port_set_host_flood(struct dsa_port *dp, bool uc, bool mc);
298+
int dsa_port_change_master(struct dsa_port *dp, struct net_device *master,
299+
struct netlink_ext_ack *extack);
295300

296301
/* slave.c */
297302
extern const struct dsa_device_ops notag_netdev_ops;
@@ -305,8 +310,12 @@ int dsa_slave_suspend(struct net_device *slave_dev);
305310
int dsa_slave_resume(struct net_device *slave_dev);
306311
int dsa_slave_register_notifier(void);
307312
void dsa_slave_unregister_notifier(void);
313+
void dsa_slave_sync_ha(struct net_device *dev);
314+
void dsa_slave_unsync_ha(struct net_device *dev);
308315
void dsa_slave_setup_tagger(struct net_device *slave);
309316
int dsa_slave_change_mtu(struct net_device *dev, int new_mtu);
317+
int dsa_slave_change_master(struct net_device *dev, struct net_device *master,
318+
struct netlink_ext_ack *extack);
310319
int dsa_slave_manage_vlan_filtering(struct net_device *dev,
311320
bool vlan_filtering);
312321

@@ -542,6 +551,7 @@ void dsa_lag_map(struct dsa_switch_tree *dst, struct dsa_lag *lag);
542551
void dsa_lag_unmap(struct dsa_switch_tree *dst, struct dsa_lag *lag);
543552
struct dsa_lag *dsa_tree_lag_find(struct dsa_switch_tree *dst,
544553
const struct net_device *lag_dev);
554+
struct net_device *dsa_tree_find_first_master(struct dsa_switch_tree *dst);
545555
int dsa_tree_notify(struct dsa_switch_tree *dst, unsigned long e, void *v);
546556
int dsa_broadcast(unsigned long e, void *v);
547557
int dsa_tree_change_tag_proto(struct dsa_switch_tree *dst,

net/dsa/netlink.c

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/* Copyright 2022 NXP
3+
*/
4+
#include <linux/netdevice.h>
5+
#include <net/rtnetlink.h>
6+
7+
#include "dsa_priv.h"
8+
9+
static const struct nla_policy dsa_policy[IFLA_DSA_MAX + 1] = {
10+
[IFLA_DSA_MASTER] = { .type = NLA_U32 },
11+
};
12+
13+
static int dsa_changelink(struct net_device *dev, struct nlattr *tb[],
14+
struct nlattr *data[],
15+
struct netlink_ext_ack *extack)
16+
{
17+
int err;
18+
19+
if (!data)
20+
return 0;
21+
22+
if (data[IFLA_DSA_MASTER]) {
23+
u32 ifindex = nla_get_u32(data[IFLA_DSA_MASTER]);
24+
struct net_device *master;
25+
26+
master = __dev_get_by_index(dev_net(dev), ifindex);
27+
if (!master)
28+
return -EINVAL;
29+
30+
err = dsa_slave_change_master(dev, master, extack);
31+
if (err)
32+
return err;
33+
}
34+
35+
return 0;
36+
}
37+
38+
static size_t dsa_get_size(const struct net_device *dev)
39+
{
40+
return nla_total_size(sizeof(u32)) + /* IFLA_DSA_MASTER */
41+
0;
42+
}
43+
44+
static int dsa_fill_info(struct sk_buff *skb, const struct net_device *dev)
45+
{
46+
struct net_device *master = dsa_slave_to_master(dev);
47+
48+
if (nla_put_u32(skb, IFLA_DSA_MASTER, master->ifindex))
49+
return -EMSGSIZE;
50+
51+
return 0;
52+
}
53+
54+
struct rtnl_link_ops dsa_link_ops __read_mostly = {
55+
.kind = "dsa",
56+
.priv_size = sizeof(struct dsa_port),
57+
.maxtype = IFLA_DSA_MAX,
58+
.policy = dsa_policy,
59+
.changelink = dsa_changelink,
60+
.get_size = dsa_get_size,
61+
.fill_info = dsa_fill_info,
62+
};

net/dsa/port.c

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
*/
88

99
#include <linux/if_bridge.h>
10+
#include <linux/netdevice.h>
1011
#include <linux/notifier.h>
1112
#include <linux/of_mdio.h>
1213
#include <linux/of_net.h>
@@ -1374,6 +1375,135 @@ int dsa_port_mrp_del_ring_role(const struct dsa_port *dp,
13741375
return ds->ops->port_mrp_del_ring_role(ds, dp->index, mrp);
13751376
}
13761377

1378+
static int dsa_port_assign_master(struct dsa_port *dp,
1379+
struct net_device *master,
1380+
struct netlink_ext_ack *extack,
1381+
bool fail_on_err)
1382+
{
1383+
struct dsa_switch *ds = dp->ds;
1384+
int port = dp->index, err;
1385+
1386+
err = ds->ops->port_change_master(ds, port, master, extack);
1387+
if (err && !fail_on_err)
1388+
dev_err(ds->dev, "port %d failed to assign master %s: %pe\n",
1389+
port, master->name, ERR_PTR(err));
1390+
1391+
if (err && fail_on_err)
1392+
return err;
1393+
1394+
dp->cpu_dp = master->dsa_ptr;
1395+
1396+
return 0;
1397+
}
1398+
1399+
/* Change the dp->cpu_dp affinity for a user port. Note that both cross-chip
1400+
* notifiers and drivers have implicit assumptions about user-to-CPU-port
1401+
* mappings, so we unfortunately cannot delay the deletion of the objects
1402+
* (switchdev, standalone addresses, standalone VLANs) on the old CPU port
1403+
* until the new CPU port has been set up. So we need to completely tear down
1404+
* the old CPU port before changing it, and restore it on errors during the
1405+
* bringup of the new one.
1406+
*/
1407+
int dsa_port_change_master(struct dsa_port *dp, struct net_device *master,
1408+
struct netlink_ext_ack *extack)
1409+
{
1410+
struct net_device *bridge_dev = dsa_port_bridge_dev_get(dp);
1411+
struct net_device *old_master = dsa_port_to_master(dp);
1412+
struct net_device *dev = dp->slave;
1413+
struct dsa_switch *ds = dp->ds;
1414+
bool vlan_filtering;
1415+
int err, tmp;
1416+
1417+
/* Bridges may hold host FDB, MDB and VLAN objects. These need to be
1418+
* migrated, so dynamically unoffload and later reoffload the bridge
1419+
* port.
1420+
*/
1421+
if (bridge_dev) {
1422+
dsa_port_pre_bridge_leave(dp, bridge_dev);
1423+
dsa_port_bridge_leave(dp, bridge_dev);
1424+
}
1425+
1426+
/* The port might still be VLAN filtering even if it's no longer
1427+
* under a bridge, either due to ds->vlan_filtering_is_global or
1428+
* ds->needs_standalone_vlan_filtering. In turn this means VLANs
1429+
* on the CPU port.
1430+
*/
1431+
vlan_filtering = dsa_port_is_vlan_filtering(dp);
1432+
if (vlan_filtering) {
1433+
err = dsa_slave_manage_vlan_filtering(dev, false);
1434+
if (err) {
1435+
NL_SET_ERR_MSG_MOD(extack,
1436+
"Failed to remove standalone VLANs");
1437+
goto rewind_old_bridge;
1438+
}
1439+
}
1440+
1441+
/* Standalone addresses, and addresses of upper interfaces like
1442+
* VLAN, LAG, HSR need to be migrated.
1443+
*/
1444+
dsa_slave_unsync_ha(dev);
1445+
1446+
err = dsa_port_assign_master(dp, master, extack, true);
1447+
if (err)
1448+
goto rewind_old_addrs;
1449+
1450+
dsa_slave_sync_ha(dev);
1451+
1452+
if (vlan_filtering) {
1453+
err = dsa_slave_manage_vlan_filtering(dev, true);
1454+
if (err) {
1455+
NL_SET_ERR_MSG_MOD(extack,
1456+
"Failed to restore standalone VLANs");
1457+
goto rewind_new_addrs;
1458+
}
1459+
}
1460+
1461+
if (bridge_dev) {
1462+
err = dsa_port_bridge_join(dp, bridge_dev, extack);
1463+
if (err && err == -EOPNOTSUPP) {
1464+
NL_SET_ERR_MSG_MOD(extack,
1465+
"Failed to reoffload bridge");
1466+
goto rewind_new_vlan;
1467+
}
1468+
}
1469+
1470+
return 0;
1471+
1472+
rewind_new_vlan:
1473+
if (vlan_filtering)
1474+
dsa_slave_manage_vlan_filtering(dev, false);
1475+
1476+
rewind_new_addrs:
1477+
dsa_slave_unsync_ha(dev);
1478+
1479+
dsa_port_assign_master(dp, old_master, NULL, false);
1480+
1481+
/* Restore the objects on the old CPU port */
1482+
rewind_old_addrs:
1483+
dsa_slave_sync_ha(dev);
1484+
1485+
if (vlan_filtering) {
1486+
tmp = dsa_slave_manage_vlan_filtering(dev, true);
1487+
if (tmp) {
1488+
dev_err(ds->dev,
1489+
"port %d failed to restore standalone VLANs: %pe\n",
1490+
dp->index, ERR_PTR(tmp));
1491+
}
1492+
}
1493+
1494+
rewind_old_bridge:
1495+
if (bridge_dev) {
1496+
tmp = dsa_port_bridge_join(dp, bridge_dev, extack);
1497+
if (tmp) {
1498+
dev_err(ds->dev,
1499+
"port %d failed to rejoin bridge %s: %pe\n",
1500+
dp->index, bridge_dev->name, ERR_PTR(tmp));
1501+
}
1502+
}
1503+
1504+
return err;
1505+
}
1506+
13771507
void dsa_port_set_tag_protocol(struct dsa_port *cpu_dp,
13781508
const struct dsa_device_ops *tag_ops)
13791509
{

0 commit comments

Comments
 (0)