| 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 |
| @@ -581,6 +581,7 @@ void br_fdb_update(struct net_bridge *br |
| |
| /* fastpath: update of existing entry */ |
| if (unlikely(source != fdb->dst && !fdb->is_sticky)) { |
| + br_switchdev_fdb_notify(fdb, RTM_DELNEIGH); |
| fdb->dst = source; |
| fdb_modified = true; |
| /* Take over HW learned entry */ |