net: switchdev: Add a helper to replay objects on a bridge port
authorPetr Machata <petrm@nvidia.com>
Wed, 19 Jul 2023 11:01:17 +0000 (13:01 +0200)
committerDavid S. Miller <davem@davemloft.net>
Fri, 21 Jul 2023 07:54:03 +0000 (08:54 +0100)
When a front panel joins a bridge via another netdevice (typically a LAG),
the driver needs to learn about the objects configured on the bridge port.
When the bridge port is offloaded by the driver for the first time, this
can be achieved by passing a notifier to switchdev_bridge_port_offload().
The notifier is then invoked for the individual objects (such as VLANs)
configured on the bridge, and can look for the interesting ones.

Calling switchdev_bridge_port_offload() when the second port joins the
bridge lower is unnecessary, but the replay is still needed. To that end,
add a new function, switchdev_bridge_port_replay(), which does only the
replay part of the _offload() function in exactly the same way as that
function.

Cc: Jiri Pirko <jiri@resnulli.us>
Cc: Ivan Vecera <ivecera@redhat.com>
Cc: Roopa Prabhu <roopa@nvidia.com>
Cc: Nikolay Aleksandrov <razor@blackwall.org>
Cc: bridge@lists.linux-foundation.org
Signed-off-by: Petr Machata <petrm@nvidia.com>
Reviewed-by: Danielle Ratson <danieller@nvidia.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/net/switchdev.h
net/bridge/br.c
net/bridge/br_private.h
net/bridge/br_switchdev.c
net/switchdev/switchdev.c

index ca0312b78294e670019ba9a12c30be95fe7177e0..4d324e2a2eef063172fdbb9bb126b83520579826 100644 (file)
@@ -231,6 +231,7 @@ enum switchdev_notifier_type {
 
        SWITCHDEV_BRPORT_OFFLOADED,
        SWITCHDEV_BRPORT_UNOFFLOADED,
+       SWITCHDEV_BRPORT_REPLAY,
 };
 
 struct switchdev_notifier_info {
@@ -299,6 +300,11 @@ void switchdev_bridge_port_unoffload(struct net_device *brport_dev,
                                     const void *ctx,
                                     struct notifier_block *atomic_nb,
                                     struct notifier_block *blocking_nb);
+int switchdev_bridge_port_replay(struct net_device *brport_dev,
+                                struct net_device *dev, const void *ctx,
+                                struct notifier_block *atomic_nb,
+                                struct notifier_block *blocking_nb,
+                                struct netlink_ext_ack *extack);
 
 void switchdev_deferred_process(void);
 int switchdev_port_attr_set(struct net_device *dev,
index 4f5098d33a46bf4345b1b50718433ba0db44ce13..a6e94ceb7c9a08b7f6f8787a490e7c0c1ddcf8d6 100644 (file)
@@ -234,6 +234,14 @@ static int br_switchdev_blocking_event(struct notifier_block *nb,
                br_switchdev_port_unoffload(p, b->ctx, b->atomic_nb,
                                            b->blocking_nb);
                break;
+       case SWITCHDEV_BRPORT_REPLAY:
+               brport_info = ptr;
+               b = &brport_info->brport;
+
+               err = br_switchdev_port_replay(p, b->dev, b->ctx, b->atomic_nb,
+                                              b->blocking_nb, extack);
+               err = notifier_from_errno(err);
+               break;
        }
 
 out:
index 05a965ef76f1a870beb093169572db4777de623c..51e4ca54b53774caaf370e47f15bbec94a4b9348 100644 (file)
@@ -2118,6 +2118,12 @@ void br_switchdev_port_unoffload(struct net_bridge_port *p, const void *ctx,
                                 struct notifier_block *atomic_nb,
                                 struct notifier_block *blocking_nb);
 
+int br_switchdev_port_replay(struct net_bridge_port *p,
+                            struct net_device *dev, const void *ctx,
+                            struct notifier_block *atomic_nb,
+                            struct notifier_block *blocking_nb,
+                            struct netlink_ext_ack *extack);
+
 bool br_switchdev_frame_uses_tx_fwd_offload(struct sk_buff *skb);
 
 void br_switchdev_frame_set_offload_fwd_mark(struct sk_buff *skb);
@@ -2168,6 +2174,16 @@ br_switchdev_port_unoffload(struct net_bridge_port *p, const void *ctx,
 {
 }
 
+static inline int
+br_switchdev_port_replay(struct net_bridge_port *p,
+                        struct net_device *dev, const void *ctx,
+                        struct notifier_block *atomic_nb,
+                        struct notifier_block *blocking_nb,
+                        struct netlink_ext_ack *extack)
+{
+       return -EOPNOTSUPP;
+}
+
 static inline bool br_switchdev_frame_uses_tx_fwd_offload(struct sk_buff *skb)
 {
        return false;
index e92e0338afee3d40a76b5eaaab8edebe81dd7659..ee84e783e1dff5b67994a3ba5a4e5d8aa875eeef 100644 (file)
@@ -829,3 +829,12 @@ void br_switchdev_port_unoffload(struct net_bridge_port *p, const void *ctx,
 
        nbp_switchdev_del(p);
 }
+
+int br_switchdev_port_replay(struct net_bridge_port *p,
+                            struct net_device *dev, const void *ctx,
+                            struct notifier_block *atomic_nb,
+                            struct notifier_block *blocking_nb,
+                            struct netlink_ext_ack *extack)
+{
+       return nbp_switchdev_sync_objs(p, ctx, atomic_nb, blocking_nb, extack);
+}
index 8cc42aea19c7ecf7cb10e516f7578b94a0ddce47..5b045284849e03151b172cf55248492aed2b3472 100644 (file)
@@ -862,3 +862,28 @@ void switchdev_bridge_port_unoffload(struct net_device *brport_dev,
                                          NULL);
 }
 EXPORT_SYMBOL_GPL(switchdev_bridge_port_unoffload);
+
+int switchdev_bridge_port_replay(struct net_device *brport_dev,
+                                struct net_device *dev, const void *ctx,
+                                struct notifier_block *atomic_nb,
+                                struct notifier_block *blocking_nb,
+                                struct netlink_ext_ack *extack)
+{
+       struct switchdev_notifier_brport_info brport_info = {
+               .brport = {
+                       .dev = dev,
+                       .ctx = ctx,
+                       .atomic_nb = atomic_nb,
+                       .blocking_nb = blocking_nb,
+               },
+       };
+       int err;
+
+       ASSERT_RTNL();
+
+       err = call_switchdev_blocking_notifiers(SWITCHDEV_BRPORT_REPLAY,
+                                               brport_dev, &brport_info.info,
+                                               extack);
+       return notifier_to_errno(err);
+}
+EXPORT_SYMBOL_GPL(switchdev_bridge_port_replay);