net: dsa: felix: avoid early deletion of host FDB entries
[linux-2.6-block.git] / net / dsa / dsa.c
index fe971a2c15cd1efaabe49df3603a02d6a9b154b7..89c6c86e746fbe990c233b70eb7fa03da9fb43ea 100644 (file)
@@ -507,6 +507,66 @@ int dsa_port_walk_mdbs(struct dsa_switch *ds, int port, dsa_fdb_walk_cb_t cb)
 }
 EXPORT_SYMBOL_GPL(dsa_port_walk_mdbs);
 
+bool dsa_db_equal(const struct dsa_db *a, const struct dsa_db *b)
+{
+       if (a->type != b->type)
+               return false;
+
+       switch (a->type) {
+       case DSA_DB_PORT:
+               return a->dp == b->dp;
+       case DSA_DB_LAG:
+               return a->lag.dev == b->lag.dev;
+       case DSA_DB_BRIDGE:
+               return a->bridge.num == b->bridge.num;
+       default:
+               WARN_ON(1);
+               return false;
+       }
+}
+
+bool dsa_fdb_present_in_other_db(struct dsa_switch *ds, int port,
+                                const unsigned char *addr, u16 vid,
+                                struct dsa_db db)
+{
+       struct dsa_port *dp = dsa_to_port(ds, port);
+       struct dsa_mac_addr *a;
+
+       lockdep_assert_held(&dp->addr_lists_lock);
+
+       list_for_each_entry(a, &dp->fdbs, list) {
+               if (!ether_addr_equal(a->addr, addr) || a->vid != vid)
+                       continue;
+
+               if (a->db.type == db.type && !dsa_db_equal(&a->db, &db))
+                       return true;
+       }
+
+       return false;
+}
+EXPORT_SYMBOL_GPL(dsa_fdb_present_in_other_db);
+
+bool dsa_mdb_present_in_other_db(struct dsa_switch *ds, int port,
+                                const struct switchdev_obj_port_mdb *mdb,
+                                struct dsa_db db)
+{
+       struct dsa_port *dp = dsa_to_port(ds, port);
+       struct dsa_mac_addr *a;
+
+       lockdep_assert_held(&dp->addr_lists_lock);
+
+       list_for_each_entry(a, &dp->mdbs, list) {
+               if (!ether_addr_equal(a->addr, mdb->addr) || a->vid != mdb->vid)
+                       continue;
+
+               if (a->db.type == db.type && !dsa_db_equal(&a->db, &db))
+                       return true;
+       }
+
+       return false;
+}
+EXPORT_SYMBOL_GPL(dsa_mdb_present_in_other_db);
+
 static int __init dsa_init_module(void)
 {
        int rc;