diff options
Diffstat (limited to 'net/bridge/br_switchdev.c')
-rw-r--r-- | net/bridge/br_switchdev.c | 75 |
1 files changed, 72 insertions, 3 deletions
diff --git a/net/bridge/br_switchdev.c b/net/bridge/br_switchdev.c index 39f0787fde01..6bfff28ede23 100644 --- a/net/bridge/br_switchdev.c +++ b/net/bridge/br_switchdev.c @@ -206,11 +206,62 @@ static void nbp_switchdev_del(struct net_bridge_port *p) nbp_switchdev_hwdom_put(p); } +static int nbp_switchdev_sync_objs(struct net_bridge_port *p, const void *ctx, + struct notifier_block *atomic_nb, + struct notifier_block *blocking_nb, + struct netlink_ext_ack *extack) +{ + struct net_device *br_dev = p->br->dev; + struct net_device *dev = p->dev; + int err; + + err = br_vlan_replay(br_dev, dev, ctx, true, blocking_nb, extack); + if (err && err != -EOPNOTSUPP) + return err; + + err = br_mdb_replay(br_dev, dev, ctx, true, blocking_nb, extack); + if (err && err != -EOPNOTSUPP) + return err; + + /* Forwarding and termination FDB entries on the port */ + err = br_fdb_replay(br_dev, dev, ctx, true, atomic_nb); + if (err && err != -EOPNOTSUPP) + return err; + + /* Termination FDB entries on the bridge itself */ + err = br_fdb_replay(br_dev, br_dev, ctx, true, atomic_nb); + if (err && err != -EOPNOTSUPP) + return err; + + return 0; +} + +static void nbp_switchdev_unsync_objs(struct net_bridge_port *p, + const void *ctx, + struct notifier_block *atomic_nb, + struct notifier_block *blocking_nb) +{ + struct net_device *br_dev = p->br->dev; + struct net_device *dev = p->dev; + + br_vlan_replay(br_dev, dev, ctx, false, blocking_nb, NULL); + + br_mdb_replay(br_dev, dev, ctx, false, blocking_nb, NULL); + + /* Forwarding and termination FDB entries on the port */ + br_fdb_replay(br_dev, dev, ctx, false, atomic_nb); + + /* Termination FDB entries on the bridge itself */ + br_fdb_replay(br_dev, br_dev, ctx, false, atomic_nb); +} + /* Let the bridge know that this port is offloaded, so that it can assign a * switchdev hardware domain to it. */ int switchdev_bridge_port_offload(struct net_device *brport_dev, - struct net_device *dev, + struct net_device *dev, const void *ctx, + struct notifier_block *atomic_nb, + struct notifier_block *blocking_nb, struct netlink_ext_ack *extack) { struct netdev_phys_item_id ppid; @@ -227,11 +278,27 @@ int switchdev_bridge_port_offload(struct net_device *brport_dev, if (err) return err; - return nbp_switchdev_add(p, ppid, extack); + err = nbp_switchdev_add(p, ppid, extack); + if (err) + return err; + + err = nbp_switchdev_sync_objs(p, ctx, atomic_nb, blocking_nb, extack); + if (err) + goto out_switchdev_del; + + return 0; + +out_switchdev_del: + nbp_switchdev_del(p); + + return err; } EXPORT_SYMBOL_GPL(switchdev_bridge_port_offload); -void switchdev_bridge_port_unoffload(struct net_device *brport_dev) +void switchdev_bridge_port_unoffload(struct net_device *brport_dev, + const void *ctx, + struct notifier_block *atomic_nb, + struct notifier_block *blocking_nb) { struct net_bridge_port *p; @@ -241,6 +308,8 @@ void switchdev_bridge_port_unoffload(struct net_device *brport_dev) if (!p) return; + nbp_switchdev_unsync_objs(p, ctx, atomic_nb, blocking_nb); + nbp_switchdev_del(p); } EXPORT_SYMBOL_GPL(switchdev_bridge_port_unoffload); |