net: dsa: add MDB support
authorVivien Didelot <vivien.didelot@savoirfairelinux.com>
Wed, 31 Aug 2016 15:50:03 +0000 (11:50 -0400)
committerDavid S. Miller <davem@davemloft.net>
Wed, 31 Aug 2016 21:15:42 +0000 (14:15 -0700)
Add SWITCHDEV_OBJ_ID_PORT_MDB support to the DSA layer.

Signed-off-by: Vivien Didelot <vivien.didelot@savoirfairelinux.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Documentation/networking/dsa/dsa.txt
include/net/dsa.h
net/dsa/slave.c

index a4e55c76d37181fcd7a585966ef97eb67dafd353..6d6c07cf1a9aed11628ac9824c65b84332a30896 100644 (file)
@@ -584,6 +584,29 @@ of DSA, would be the its port-based VLAN, used by the associated bridge device.
   function that the driver has to call for each MAC address known to be behind
   the given port. A switchdev object is used to carry the VID and FDB info.
 
+- port_mdb_prepare: bridge layer function invoked when the bridge prepares the
+  installation of a multicast database entry. If the operation is not supported,
+  this function should return -EOPNOTSUPP to inform the bridge code to fallback
+  to a software implementation. No hardware setup must be done in this function.
+  See port_fdb_add for this and details.
+
+- port_mdb_add: bridge layer function invoked when the bridge wants to install
+  a multicast database entry, the switch hardware should be programmed with the
+  specified address in the specified VLAN ID in the forwarding database
+  associated with this VLAN ID.
+
+Note: VLAN ID 0 corresponds to the port private database, which, in the context
+of DSA, would be the its port-based VLAN, used by the associated bridge device.
+
+- port_mdb_del: bridge layer function invoked when the bridge wants to remove a
+  multicast database entry, the switch hardware should be programmed to delete
+  the specified MAC address from the specified VLAN ID if it was mapped into
+  this port forwarding database.
+
+- port_mdb_dump: bridge layer function invoked with a switchdev callback
+  function that the driver has to call for each MAC address known to be behind
+  the given port. A switchdev object is used to carry the VID and MDB info.
+
 TODO
 ====
 
index 2ebeba44a4619bb6a2b03221b1ec95b9cf68f230..e3eb230b970d5f481f8ecec053571b2c4061c1b8 100644 (file)
@@ -234,6 +234,7 @@ static inline u8 dsa_upstream_port(struct dsa_switch *ds)
 struct switchdev_trans;
 struct switchdev_obj;
 struct switchdev_obj_port_fdb;
+struct switchdev_obj_port_mdb;
 struct switchdev_obj_port_vlan;
 
 struct dsa_switch_ops {
@@ -369,6 +370,21 @@ struct dsa_switch_ops {
        int     (*port_fdb_dump)(struct dsa_switch *ds, int port,
                                 struct switchdev_obj_port_fdb *fdb,
                                 int (*cb)(struct switchdev_obj *obj));
+
+       /*
+        * Multicast database
+        */
+       int     (*port_mdb_prepare)(struct dsa_switch *ds, int port,
+                                   const struct switchdev_obj_port_mdb *mdb,
+                                   struct switchdev_trans *trans);
+       void    (*port_mdb_add)(struct dsa_switch *ds, int port,
+                               const struct switchdev_obj_port_mdb *mdb,
+                               struct switchdev_trans *trans);
+       int     (*port_mdb_del)(struct dsa_switch *ds, int port,
+                               const struct switchdev_obj_port_mdb *mdb);
+       int     (*port_mdb_dump)(struct dsa_switch *ds, int port,
+                                struct switchdev_obj_port_mdb *mdb,
+                                int (*cb)(struct switchdev_obj *obj));
 };
 
 void register_switch_driver(struct dsa_switch_ops *type);
index 9f6c2a20f6ff8a5900997d43d879c08bbbd8dca4..9ecbe787f102931f5b730d129ffe13bfa59868de 100644 (file)
@@ -290,6 +290,50 @@ static int dsa_slave_port_fdb_dump(struct net_device *dev,
        return -EOPNOTSUPP;
 }
 
+static int dsa_slave_port_mdb_add(struct net_device *dev,
+                                 const struct switchdev_obj_port_mdb *mdb,
+                                 struct switchdev_trans *trans)
+{
+       struct dsa_slave_priv *p = netdev_priv(dev);
+       struct dsa_switch *ds = p->parent;
+
+       if (switchdev_trans_ph_prepare(trans)) {
+               if (!ds->ops->port_mdb_prepare || !ds->ops->port_mdb_add)
+                       return -EOPNOTSUPP;
+
+               return ds->ops->port_mdb_prepare(ds, p->port, mdb, trans);
+       }
+
+       ds->ops->port_mdb_add(ds, p->port, mdb, trans);
+
+       return 0;
+}
+
+static int dsa_slave_port_mdb_del(struct net_device *dev,
+                                 const struct switchdev_obj_port_mdb *mdb)
+{
+       struct dsa_slave_priv *p = netdev_priv(dev);
+       struct dsa_switch *ds = p->parent;
+
+       if (ds->ops->port_mdb_del)
+               return ds->ops->port_mdb_del(ds, p->port, mdb);
+
+       return -EOPNOTSUPP;
+}
+
+static int dsa_slave_port_mdb_dump(struct net_device *dev,
+                                  struct switchdev_obj_port_mdb *mdb,
+                                  switchdev_obj_dump_cb_t *cb)
+{
+       struct dsa_slave_priv *p = netdev_priv(dev);
+       struct dsa_switch *ds = p->parent;
+
+       if (ds->ops->port_mdb_dump)
+               return ds->ops->port_mdb_dump(ds, p->port, mdb, cb);
+
+       return -EOPNOTSUPP;
+}
+
 static int dsa_slave_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 {
        struct dsa_slave_priv *p = netdev_priv(dev);
@@ -412,6 +456,10 @@ static int dsa_slave_port_obj_add(struct net_device *dev,
                                             SWITCHDEV_OBJ_PORT_FDB(obj),
                                             trans);
                break;
+       case SWITCHDEV_OBJ_ID_PORT_MDB:
+               err = dsa_slave_port_mdb_add(dev, SWITCHDEV_OBJ_PORT_MDB(obj),
+                                            trans);
+               break;
        case SWITCHDEV_OBJ_ID_PORT_VLAN:
                err = dsa_slave_port_vlan_add(dev,
                                              SWITCHDEV_OBJ_PORT_VLAN(obj),
@@ -435,6 +483,9 @@ static int dsa_slave_port_obj_del(struct net_device *dev,
                err = dsa_slave_port_fdb_del(dev,
                                             SWITCHDEV_OBJ_PORT_FDB(obj));
                break;
+       case SWITCHDEV_OBJ_ID_PORT_MDB:
+               err = dsa_slave_port_mdb_del(dev, SWITCHDEV_OBJ_PORT_MDB(obj));
+               break;
        case SWITCHDEV_OBJ_ID_PORT_VLAN:
                err = dsa_slave_port_vlan_del(dev,
                                              SWITCHDEV_OBJ_PORT_VLAN(obj));
@@ -459,6 +510,10 @@ static int dsa_slave_port_obj_dump(struct net_device *dev,
                                              SWITCHDEV_OBJ_PORT_FDB(obj),
                                              cb);
                break;
+       case SWITCHDEV_OBJ_ID_PORT_MDB:
+               err = dsa_slave_port_mdb_dump(dev, SWITCHDEV_OBJ_PORT_MDB(obj),
+                                             cb);
+               break;
        case SWITCHDEV_OBJ_ID_PORT_VLAN:
                err = dsa_slave_port_vlan_dump(dev,
                                               SWITCHDEV_OBJ_PORT_VLAN(obj),