a3bfec59ab7db156f4702e37ccb642fe65f05d5e
[openwrt/staging/svanheule.git] /
1 From: Vladimir Oltean <vladimir.oltean@nxp.com>
2 Date: Fri, 12 Feb 2021 17:15:54 +0200
3 Subject: [PATCH] net: dsa: configure better brport flags when ports leave the
4 bridge
5
6 Bugfixed version of upstream commit 5e38c15856e9 ("net: dsa: configure
7 better brport flags when ports leave the bridge")
8
9 For a DSA switch port operating in standalone mode, address learning
10 doesn't make much sense since that is a bridge function. In fact,
11 address learning even breaks setups such as this one:
12
13 +---------------------------------------------+
14 | |
15 | +-------------------+ |
16 | | br0 | send receive |
17 | +--------+-+--------+ +--------+ +--------+ |
18 | | | | | | | | | |
19 | | swp0 | | swp1 | | swp2 | | swp3 | |
20 | | | | | | | | | |
21 +-+--------+-+--------+-+--------+-+--------+-+
22 | ^ | ^
23 | | | |
24 | +-----------+ |
25 | |
26 +--------------------------------+
27
28 because if the switch has a single FDB (can offload a single bridge)
29 then source address learning on swp3 can "steal" the source MAC address
30 of swp2 from br0's FDB, because learning frames coming from swp2 will be
31 done twice: first on the swp1 ingress port, second on the swp3 ingress
32 port. So the hardware FDB will become out of sync with the software
33 bridge, and when swp2 tries to send one more packet towards swp1, the
34 ASIC will attempt to short-circuit the forwarding path and send it
35 directly to swp3 (since that's the last port it learned that address on),
36 which it obviously can't, because swp3 operates in standalone mode.
37
38 So DSA drivers operating in standalone mode should still configure a
39 list of bridge port flags even when they are standalone. Currently DSA
40 attempts to call dsa_port_bridge_flags with 0, which disables egress
41 flooding of unknown unicast and multicast, something which doesn't make
42 much sense. For the switches that implement .port_egress_floods - b53
43 and mv88e6xxx, it probably doesn't matter too much either, since they
44 can possibly inject traffic from the CPU into a standalone port,
45 regardless of MAC DA, even if egress flooding is turned off for that
46 port, but certainly not all DSA switches can do that - sja1105, for
47 example, can't. So it makes sense to use a better common default there,
48 such as "flood everything".
49
50 It should also be noted that what DSA calls "dsa_port_bridge_flags()"
51 is a degenerate name for just calling .port_egress_floods(), since
52 nothing else is implemented - not learning, in particular. But disabling
53 address learning, something that this driver is also coding up for, will
54 be supported by individual drivers once .port_egress_floods is replaced
55 with a more generic .port_bridge_flags.
56
57 Previous attempts to code up this logic have been in the common bridge
58 layer, but as pointed out by Ido Schimmel, there are corner cases that
59 are missed when doing that:
60 https://patchwork.kernel.org/project/netdevbpf/patch/20210209151936.97382-5-olteanv@gmail.com/
61
62 So, at least for now, let's leave DSA in charge of setting port flags
63 before and after the bridge join and leave.
64
65 Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
66 Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
67 Signed-off-by: David S. Miller <davem@davemloft.net>
68 [ backport and bugfix: break dsa_port_bridge_flags() out of loop ]
69 Signed-off-by: Bjørn Mork <bjorn@mork.no>
70 ---
71 net/dsa/port.c | 45 ++++++++++++++++++++++++++++++++++++++-------
72 1 file changed, 38 insertions(+), 7 deletions(-)
73
74 --- a/net/dsa/port.c
75 +++ b/net/dsa/port.c
76 @@ -134,6 +134,27 @@ void dsa_port_disable(struct dsa_port *d
77 rtnl_unlock();
78 }
79
80 +static void dsa_port_change_brport_flags(struct dsa_port *dp,
81 + bool bridge_offload)
82 +{
83 + unsigned long mask, flags;
84 + int flag, err;
85 +
86 + mask = BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD | BR_BCAST_FLOOD;
87 + if (bridge_offload)
88 + flags = mask;
89 + else
90 + flags = mask & ~BR_LEARNING;
91 +
92 + for_each_set_bit(flag, &mask, 32) {
93 + err = dsa_port_pre_bridge_flags(dp, BIT(flag), NULL, NULL);
94 + if (err)
95 + flags &= ~BIT(flag);
96 + }
97 +
98 + dsa_port_bridge_flags(dp, flags, NULL, NULL);
99 +}
100 +
101 int dsa_port_bridge_join(struct dsa_port *dp, struct net_device *br)
102 {
103 struct dsa_notifier_bridge_info info = {
104 @@ -144,10 +165,10 @@ int dsa_port_bridge_join(struct dsa_port
105 };
106 int err;
107
108 - /* Set the flooding mode before joining the port in the switch */
109 - err = dsa_port_bridge_flags(dp, BR_FLOOD | BR_MCAST_FLOOD, NULL, NULL);
110 - if (err)
111 - return err;
112 + /* Notify the port driver to set its configurable flags in a way that
113 + * matches the initial settings of a bridge port.
114 + */
115 + dsa_port_change_brport_flags(dp, true);
116
117 /* Here the interface is already bridged. Reflect the current
118 * configuration so that drivers can program their chips accordingly.
119 @@ -158,7 +179,7 @@ int dsa_port_bridge_join(struct dsa_port
120
121 /* The bridging is rolled back on error */
122 if (err) {
123 - dsa_port_bridge_flags(dp, 0, NULL, NULL);
124 + dsa_port_change_brport_flags(dp, false);
125 dp->bridge_dev = NULL;
126 }
127
128 @@ -184,8 +205,18 @@ void dsa_port_bridge_leave(struct dsa_po
129 if (err)
130 pr_err("DSA: failed to notify DSA_NOTIFIER_BRIDGE_LEAVE\n");
131
132 - /* Port is leaving the bridge, disable flooding */
133 - dsa_port_bridge_flags(dp, 0, NULL, NULL);
134 + /* Configure the port for standalone mode (no address learning,
135 + * flood everything).
136 + * The bridge only emits SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS events
137 + * when the user requests it through netlink or sysfs, but not
138 + * automatically at port join or leave, so we need to handle resetting
139 + * the brport flags ourselves. But we even prefer it that way, because
140 + * otherwise, some setups might never get the notification they need,
141 + * for example, when a port leaves a LAG that offloads the bridge,
142 + * it becomes standalone, but as far as the bridge is concerned, no
143 + * port ever left.
144 + */
145 + dsa_port_change_brport_flags(dp, false);
146
147 /* Port left the bridge, put in BR_STATE_DISABLED by the bridge layer,
148 * so allow it to be in BR_STATE_FORWARDING to be kept functional