summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStephen Hemminger <shemminger@osdl.org>2003-04-29 10:58:15 -0700
committerDavid S. Miller <davem@nuts.ninka.net>2003-04-29 10:58:15 -0700
commita8c505ffbe4b0820787119a0d7e9d539e8d6e393 (patch)
tree28d2fe9be4f693694867bc49907bad75c675bfcb
parent07211edd92071318cabb7f606cca4febe2167f65 (diff)
[BRIDGE}: Change bridge forwarding table to use hlist.
-rw-r--r--include/linux/list.h4
-rw-r--r--net/bridge/br_fdb.c113
-rw-r--r--net/bridge/br_private.h5
3 files changed, 51 insertions, 71 deletions
diff --git a/include/linux/list.h b/include/linux/list.h
index a724f9bcbe4d..11b8674c14ff 100644
--- a/include/linux/list.h
+++ b/include/linux/list.h
@@ -437,6 +437,10 @@ static __inline__ void hlist_add_before(struct hlist_node *n, struct hlist_node
for (pos = (head)->first; pos; \
pos = pos->next)
+#define hlist_for_each_safe(pos, n, head) \
+ for (pos = (head)->first; n = pos ? pos->next : 0, pos; \
+ pos = n)
+
#else
#warning "don't include kernel headers in userspace"
#endif /* __KERNEL__ */
diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c
index 78d587584620..fc26712d2149 100644
--- a/net/bridge/br_fdb.c
+++ b/net/bridge/br_fdb.c
@@ -68,28 +68,6 @@ static __inline__ int br_mac_hash(unsigned char *mac)
return x & (BR_HASH_SIZE - 1);
}
-static __inline__ void __hash_link(struct net_bridge *br,
- struct net_bridge_fdb_entry *ent,
- int hash)
-{
- ent->next_hash = br->hash[hash];
- if (ent->next_hash != NULL)
- ent->next_hash->pprev_hash = &ent->next_hash;
- br->hash[hash] = ent;
- ent->pprev_hash = &br->hash[hash];
-}
-
-static __inline__ void __hash_unlink(struct net_bridge_fdb_entry *ent)
-{
- *(ent->pprev_hash) = ent->next_hash;
- if (ent->next_hash != NULL)
- ent->next_hash->pprev_hash = ent->pprev_hash;
- ent->next_hash = NULL;
- ent->pprev_hash = NULL;
-}
-
-
-
void br_fdb_changeaddr(struct net_bridge_port *p, unsigned char *newaddr)
{
struct net_bridge *br;
@@ -99,22 +77,24 @@ void br_fdb_changeaddr(struct net_bridge_port *p, unsigned char *newaddr)
br = p->br;
write_lock_bh(&br->hash_lock);
for (i=0;i<BR_HASH_SIZE;i++) {
- struct net_bridge_fdb_entry *f;
+ struct hlist_node *h;
+
+ hlist_for_each(h, &br->hash[i]) {
+ struct net_bridge_fdb_entry *f
+ = hlist_entry(h, struct net_bridge_fdb_entry, hlist);
- f = br->hash[i];
- while (f != NULL) {
if (f->dst == p && f->is_local) {
memcpy(f->addr.addr, newaddr, ETH_ALEN);
if (newhash != i) {
- __hash_unlink(f);
- __hash_link(br, f, newhash);
+ hlist_del(&f->hlist);
+ hlist_add_head(&f->hlist,
+ &br->hash[newhash]);
}
- write_unlock_bh(&br->hash_lock);
- return;
+ goto out;
}
- f = f->next_hash;
}
}
+ out:
write_unlock_bh(&br->hash_lock);
}
@@ -127,19 +107,16 @@ void br_fdb_cleanup(struct net_bridge *br)
write_lock_bh(&br->hash_lock);
for (i=0;i<BR_HASH_SIZE;i++) {
- struct net_bridge_fdb_entry *f;
-
- f = br->hash[i];
- while (f != NULL) {
- struct net_bridge_fdb_entry *g;
-
- g = f->next_hash;
+ 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 (!f->is_static &&
time_before_eq(f->ageing_timer, timeout)) {
- __hash_unlink(f);
+ hlist_del(&f->hlist);
br_fdb_put(f);
}
- f = g;
}
}
write_unlock_bh(&br->hash_lock);
@@ -151,18 +128,15 @@ void br_fdb_delete_by_port(struct net_bridge *br, struct net_bridge_port *p)
write_lock_bh(&br->hash_lock);
for (i=0;i<BR_HASH_SIZE;i++) {
- struct net_bridge_fdb_entry *f;
-
- f = br->hash[i];
- while (f != NULL) {
- struct net_bridge_fdb_entry *g;
-
- g = f->next_hash;
+ 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 (f->dst == p) {
- __hash_unlink(f);
+ hlist_del(&f->hlist);
br_fdb_put(f);
}
- f = g;
}
}
write_unlock_bh(&br->hash_lock);
@@ -170,25 +144,24 @@ void br_fdb_delete_by_port(struct net_bridge *br, struct net_bridge_port *p)
struct net_bridge_fdb_entry *br_fdb_get(struct net_bridge *br, unsigned char *addr)
{
- struct net_bridge_fdb_entry *fdb;
+ struct hlist_node *h;
read_lock_bh(&br->hash_lock);
- fdb = br->hash[br_mac_hash(addr)];
- while (fdb != NULL) {
+
+ hlist_for_each(h, &br->hash[br_mac_hash(addr)]) {
+ struct net_bridge_fdb_entry *fdb
+ = hlist_entry(h, struct net_bridge_fdb_entry, hlist);
+
if (!memcmp(fdb->addr.addr, addr, ETH_ALEN)) {
- if (!has_expired(br, fdb)) {
- atomic_inc(&fdb->use_count);
- read_unlock_bh(&br->hash_lock);
- return fdb;
- }
+ if (has_expired(br, fdb))
+ goto ret_null;
+ atomic_inc(&fdb->use_count);
read_unlock_bh(&br->hash_lock);
- return NULL;
+ return fdb;
}
-
- fdb = fdb->next_hash;
}
-
+ ret_null:
read_unlock_bh(&br->hash_lock);
return NULL;
}
@@ -213,12 +186,16 @@ int br_fdb_get_entries(struct net_bridge *br,
read_lock_bh(&br->hash_lock);
for (i=0;i<BR_HASH_SIZE;i++) {
- struct net_bridge_fdb_entry *f;
-
- for (f = br->hash[i]; f != NULL && num < maxnum;
- f = f->next_hash) {
+ struct hlist_node *h;
+
+ hlist_for_each(h, &br->hash[i]) {
+ struct net_bridge_fdb_entry *f
+ = hlist_entry(h, struct net_bridge_fdb_entry, hlist);
struct __fdb_entry ent;
+ if (num >= maxnum)
+ goto out;
+
if (has_expired(br, f))
continue;
@@ -277,14 +254,15 @@ void br_fdb_insert(struct net_bridge *br,
unsigned char *addr,
int is_local)
{
+ struct hlist_node *h;
struct net_bridge_fdb_entry *fdb;
int hash;
hash = br_mac_hash(addr);
write_lock_bh(&br->hash_lock);
- fdb = br->hash[hash];
- while (fdb != NULL) {
+ hlist_for_each(h, &br->hash[hash]) {
+ fdb = hlist_entry(h, struct net_bridge_fdb_entry, hlist);
if (!fdb->is_local &&
!memcmp(fdb->addr.addr, addr, ETH_ALEN)) {
__fdb_possibly_replace(fdb, source, is_local);
@@ -292,7 +270,6 @@ void br_fdb_insert(struct net_bridge *br,
return;
}
- fdb = fdb->next_hash;
}
fdb = kmalloc(sizeof(*fdb), GFP_ATOMIC);
@@ -308,7 +285,7 @@ void br_fdb_insert(struct net_bridge *br,
fdb->is_static = is_local;
fdb->ageing_timer = jiffies;
- __hash_link(br, fdb, hash);
+ hlist_add_head(&fdb->hlist, &br->hash[hash]);
write_unlock_bh(&br->hash_lock);
}
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index aff11add0268..5ddd034fa0fe 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -43,8 +43,7 @@ struct mac_addr
struct net_bridge_fdb_entry
{
- struct net_bridge_fdb_entry *next_hash;
- struct net_bridge_fdb_entry **pprev_hash;
+ struct hlist_node hlist;
atomic_t use_count;
mac_addr addr;
struct net_bridge_port *dst;
@@ -86,7 +85,7 @@ struct net_bridge
struct net_device dev;
struct net_device_stats statistics;
rwlock_t hash_lock;
- struct net_bridge_fdb_entry *hash[BR_HASH_SIZE];
+ struct hlist_head hash[BR_HASH_SIZE];
struct timer_list tick;
/* STP */