]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blobdiff - net/bridge/br_switchdev.c
Merge tag 'openrisc-for-linus' of git://github.com/openrisc/linux
[mirror_ubuntu-bionic-kernel.git] / net / bridge / br_switchdev.c
index f4097b900de1ff51a9d29c967c370c916c6092f5..181a44d0f1da6364a8965b54cf13aa6a5e44ef22 100644 (file)
@@ -55,3 +55,79 @@ bool nbp_switchdev_allowed_egress(const struct net_bridge_port *p,
        return !skb->offload_fwd_mark ||
               BR_INPUT_SKB_CB(skb)->offload_fwd_mark != p->offload_fwd_mark;
 }
+
+/* Flags that can be offloaded to hardware */
+#define BR_PORT_FLAGS_HW_OFFLOAD (BR_LEARNING | BR_FLOOD | \
+                                 BR_MCAST_FLOOD | BR_BCAST_FLOOD)
+
+int br_switchdev_set_port_flag(struct net_bridge_port *p,
+                              unsigned long flags,
+                              unsigned long mask)
+{
+       struct switchdev_attr attr = {
+               .orig_dev = p->dev,
+               .id = SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS_SUPPORT,
+       };
+       int err;
+
+       if (mask & ~BR_PORT_FLAGS_HW_OFFLOAD)
+               return 0;
+
+       err = switchdev_port_attr_get(p->dev, &attr);
+       if (err == -EOPNOTSUPP)
+               return 0;
+       if (err)
+               return err;
+
+       /* Check if specific bridge flag attribute offload is supported */
+       if (!(attr.u.brport_flags_support & mask)) {
+               br_warn(p->br, "bridge flag offload is not supported %u(%s)\n",
+                       (unsigned int)p->port_no, p->dev->name);
+               return -EOPNOTSUPP;
+       }
+
+       attr.id = SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS;
+       attr.flags = SWITCHDEV_F_DEFER;
+       attr.u.brport_flags = flags;
+       err = switchdev_port_attr_set(p->dev, &attr);
+       if (err) {
+               br_warn(p->br, "error setting offload flag on port %u(%s)\n",
+                       (unsigned int)p->port_no, p->dev->name);
+               return err;
+       }
+
+       return 0;
+}
+
+static void
+br_switchdev_fdb_call_notifiers(bool adding, const unsigned char *mac,
+                               u16 vid, struct net_device *dev)
+{
+       struct switchdev_notifier_fdb_info info;
+       unsigned long notifier_type;
+
+       info.addr = mac;
+       info.vid = vid;
+       notifier_type = adding ? SWITCHDEV_FDB_ADD_TO_DEVICE : SWITCHDEV_FDB_DEL_TO_DEVICE;
+       call_switchdev_notifiers(notifier_type, dev, &info.info);
+}
+
+void
+br_switchdev_fdb_notify(const struct net_bridge_fdb_entry *fdb, int type)
+{
+       if (!fdb->added_by_user)
+               return;
+
+       switch (type) {
+       case RTM_DELNEIGH:
+               br_switchdev_fdb_call_notifiers(false, fdb->addr.addr,
+                                               fdb->vlan_id,
+                                               fdb->dst->dev);
+               break;
+       case RTM_NEWNEIGH:
+               br_switchdev_fdb_call_notifiers(true, fdb->addr.addr,
+                                               fdb->vlan_id,
+                                               fdb->dst->dev);
+               break;
+       }
+}