--- zzzz-none-000/linux-2.6.13.1/net/bridge/br_fdb.c 2005-09-10 02:42:58.000000000 +0000 +++ ohio-7170-487/linux-2.6.13.1/net/bridge/br_fdb.c 2009-01-07 13:09:01.000000000 +0000 @@ -23,7 +23,7 @@ #include #include "br_private.h" -static kmem_cache_t *br_fdb_cache; +static kmem_cache_t *br_fdb_cache __read_mostly; static int fdb_insert(struct net_bridge *br, struct net_bridge_port *source, const unsigned char *addr); @@ -86,8 +86,8 @@ struct net_bridge_port *op; list_for_each_entry(op, &br->port_list, list) { if (op != p && - !memcmp(op->dev->dev_addr, - f->addr.addr, ETH_ALEN)) { + !compare_ether_addr(op->dev->dev_addr, + f->addr.addr)) { f->dst = op; goto insert; } @@ -151,8 +151,8 @@ struct net_bridge_port *op; list_for_each_entry(op, &br->port_list, list) { if (op != p && - !memcmp(op->dev->dev_addr, - f->addr.addr, ETH_ALEN)) { + !compare_ether_addr(op->dev->dev_addr, + f->addr.addr)) { f->dst = op; goto skip_delete; } @@ -166,6 +166,29 @@ spin_unlock_bh(&br->hash_lock); } +void br_fdb_delete_by_mac_if_local_without_port(struct net_bridge *br, unsigned char *addr) +{ + int i; + + spin_lock_bh(&br->hash_lock); + for (i = 0; i < BR_HASH_SIZE; i++) { + struct hlist_node *h, *g; + + hlist_for_each_safe(h, g, &br->hash[i]) { + struct net_bridge_fdb_entry *f + = hlist_entry(h, struct net_bridge_fdb_entry, hlist); + if (0 == f->dst && f->is_local && !compare_ether_addr(f->addr.addr, addr)) { + fdb_delete(f); + goto end; + } + } + } +end: + spin_unlock_bh(&br->hash_lock); +} + + + /* No locking or refcounting, assumes caller has no preempt (rcu_read_lock) */ struct net_bridge_fdb_entry *__br_fdb_get(struct net_bridge *br, const unsigned char *addr) @@ -174,7 +197,7 @@ struct net_bridge_fdb_entry *fdb; hlist_for_each_entry_rcu(fdb, h, &br->hash[br_mac_hash(addr)], hlist) { - if (!memcmp(fdb->addr.addr, addr, ETH_ALEN)) { + if (!compare_ether_addr(fdb->addr.addr, addr)) { if (unlikely(has_expired(br, fdb))) break; return fdb; @@ -234,6 +257,9 @@ if (has_expired(br, f)) continue; + + if (!f->dst) + continue; if (skip) { --skip; @@ -264,7 +290,7 @@ struct net_bridge_fdb_entry *fdb; hlist_for_each_entry_rcu(fdb, h, head, hlist) { - if (!memcmp(fdb->addr.addr, addr, ETH_ALEN)) + if (!compare_ether_addr(fdb->addr.addr, addr)) return fdb; } return NULL; @@ -283,7 +309,7 @@ atomic_set(&fdb->use_count, 1); hlist_add_head_rcu(&fdb->hlist, head); - fdb->dst = source; + fdb->dst = source; /* AVM: note that source may be 0 if is_local */ fdb->is_local = is_local; fdb->is_static = is_local; fdb->ageing_timer = jiffies; @@ -310,7 +336,7 @@ printk(KERN_WARNING "%s adding interface with same address " "as a received packet\n", - source->dev->name); + source ? source->dev->name : ""); fdb_delete(fdb); }