aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/generic/backport-5.15/720-v5.12-net-bridge-notify-switchdev-of-disappearance-of-old-.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/generic/backport-5.15/720-v5.12-net-bridge-notify-switchdev-of-disappearance-of-old-.patch')
-rw-r--r--target/linux/generic/backport-5.15/720-v5.12-net-bridge-notify-switchdev-of-disappearance-of-old-.patch126
1 files changed, 126 insertions, 0 deletions
diff --git a/target/linux/generic/backport-5.15/720-v5.12-net-bridge-notify-switchdev-of-disappearance-of-old-.patch b/target/linux/generic/backport-5.15/720-v5.12-net-bridge-notify-switchdev-of-disappearance-of-old-.patch
new file mode 100644
index 0000000000..c43cb4d1f2
--- /dev/null
+++ b/target/linux/generic/backport-5.15/720-v5.12-net-bridge-notify-switchdev-of-disappearance-of-old-.patch
@@ -0,0 +1,126 @@
+From 90dc8fd36078a536671adae884d0b929cce6480a Mon Sep 17 00:00:00 2001
+From: Vladimir Oltean <vladimir.oltean@nxp.com>
+Date: Wed, 6 Jan 2021 11:51:30 +0200
+Subject: [PATCH] net: bridge: notify switchdev of disappearance of old FDB
+ entry upon migration
+
+Currently the bridge emits atomic switchdev notifications for
+dynamically learnt FDB entries. Monitoring these notifications works
+wonders for switchdev drivers that want to keep their hardware FDB in
+sync with the bridge's FDB.
+
+For example station A wants to talk to station B in the diagram below,
+and we are concerned with the behavior of the bridge on the DUT device:
+
+ DUT
+ +-------------------------------------+
+ | br0 |
+ | +------+ +------+ +------+ +------+ |
+ | | | | | | | | | |
+ | | swp0 | | swp1 | | swp2 | | eth0 | |
+ +-------------------------------------+
+ | | |
+ Station A | |
+ | |
+ +--+------+--+ +--+------+--+
+ | | | | | | | |
+ | | swp0 | | | | swp0 | |
+ Another | +------+ | | +------+ | Another
+ switch | br0 | | br0 | switch
+ | +------+ | | +------+ |
+ | | | | | | | |
+ | | swp1 | | | | swp1 | |
+ +--+------+--+ +--+------+--+
+ |
+ Station B
+
+Interfaces swp0, swp1, swp2 are handled by a switchdev driver that has
+the following property: frames injected from its control interface bypass
+the internal address analyzer logic, and therefore, this hardware does
+not learn from the source address of packets transmitted by the network
+stack through it. So, since bridging between eth0 (where Station B is
+attached) and swp0 (where Station A is attached) is done in software,
+the switchdev hardware will never learn the source address of Station B.
+So the traffic towards that destination will be treated as unknown, i.e.
+flooded.
+
+This is where the bridge notifications come in handy. When br0 on the
+DUT sees frames with Station B's MAC address on eth0, the switchdev
+driver gets these notifications and can install a rule to send frames
+towards Station B's address that are incoming from swp0, swp1, swp2,
+only towards the control interface. This is all switchdev driver private
+business, which the notification makes possible.
+
+All is fine until someone unplugs Station B's cable and moves it to the
+other switch:
+
+ DUT
+ +-------------------------------------+
+ | br0 |
+ | +------+ +------+ +------+ +------+ |
+ | | | | | | | | | |
+ | | swp0 | | swp1 | | swp2 | | eth0 | |
+ +-------------------------------------+
+ | | |
+ Station A | |
+ | |
+ +--+------+--+ +--+------+--+
+ | | | | | | | |
+ | | swp0 | | | | swp0 | |
+ Another | +------+ | | +------+ | Another
+ switch | br0 | | br0 | switch
+ | +------+ | | +------+ |
+ | | | | | | | |
+ | | swp1 | | | | swp1 | |
+ +--+------+--+ +--+------+--+
+ |
+ Station B
+
+Luckily for the use cases we care about, Station B is noisy enough that
+the DUT hears it (on swp1 this time). swp1 receives the frames and
+delivers them to the bridge, who enters the unlikely path in br_fdb_update
+of updating an existing entry. It moves the entry in the software bridge
+to swp1 and emits an addition notification towards that.
+
+As far as the switchdev driver is concerned, all that it needs to ensure
+is that traffic between Station A and Station B is not forever broken.
+If it does nothing, then the stale rule to send frames for Station B
+towards the control interface remains in place. But Station B is no
+longer reachable via the control interface, but via a port that can
+offload the bridge port learning attribute. It's just that the port is
+prevented from learning this address, since the rule overrides FDB
+updates. So the rule needs to go. The question is via what mechanism.
+
+It sure would be possible for this switchdev driver to keep track of all
+addresses which are sent to the control interface, and then also listen
+for bridge notifier events on its own ports, searching for the ones that
+have a MAC address which was previously sent to the control interface.
+But this is cumbersome and inefficient. Instead, with one small change,
+the bridge could notify of the address deletion from the old port, in a
+symmetrical manner with how it did for the insertion. Then the switchdev
+driver would not be required to monitor learn/forget events for its own
+ports. It could just delete the rule towards the control interface upon
+bridge entry migration. This would make hardware address learning be
+possible again. Then it would take a few more packets until the hardware
+and software FDB would be in sync again.
+
+Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+Acked-by: Nikolay Aleksandrov <nikolay@nvidia.com>
+Reviewed-by: Ido Schimmel <idosch@nvidia.com>
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ net/bridge/br_fdb.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/net/bridge/br_fdb.c
++++ b/net/bridge/br_fdb.c
+@@ -602,6 +602,7 @@ void br_fdb_update(struct net_bridge *br
+ /* fastpath: update of existing entry */
+ if (unlikely(source != fdb->dst &&
+ !test_bit(BR_FDB_STICKY, &fdb->flags))) {
++ br_switchdev_fdb_notify(fdb, RTM_DELNEIGH);
+ fdb->dst = source;
+ fdb_modified = true;
+ /* Take over HW learned entry */