3 * Linux ethernet bridge
6 * Lennert Buytenhek <buytenh@gnu.org>
8 * $Id: br_fdb.c,v 1.5.2.1 2002/01/17 00:59:01 davem Exp $
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version
13 * 2 of the License, or (at your option) any later version.
16 #include <linux/kernel.h>
17 #include <linux/spinlock.h>
18 #include <linux/if_bridge.h>
19 #include <asm/atomic.h>
20 #include <asm/uaccess.h>
21 #include "br_private.h"
23 static __inline__ unsigned long __timeout(struct net_bridge *br)
25 unsigned long timeout;
27 timeout = jiffies - br->ageing_time;
28 if (br->topology_change)
29 timeout = jiffies - br->forward_delay;
34 static __inline__ int has_expired(struct net_bridge *br,
35 struct net_bridge_fdb_entry *fdb)
37 if (!fdb->is_static &&
38 time_before_eq(fdb->ageing_timer, __timeout(br)))
44 static __inline__ void copy_fdb(struct __fdb_entry *ent, struct net_bridge_fdb_entry *f)
46 memset(ent, 0, sizeof(struct __fdb_entry));
47 memcpy(ent->mac_addr, f->addr.addr, ETH_ALEN);
48 ent->port_no = f->dst?f->dst->port_no:0;
49 ent->is_local = f->is_local;
50 ent->ageing_timer_value = 0;
52 ent->ageing_timer_value = jiffies - f->ageing_timer;
55 static __inline__ int br_mac_hash(unsigned char *mac)
60 x = (x << 2) ^ mac[1];
61 x = (x << 2) ^ mac[2];
62 x = (x << 2) ^ mac[3];
63 x = (x << 2) ^ mac[4];
64 x = (x << 2) ^ mac[5];
68 return x & (BR_HASH_SIZE - 1);
71 static __inline__ void __hash_link(struct net_bridge *br,
72 struct net_bridge_fdb_entry *ent,
75 ent->next_hash = br->hash[hash];
76 if (ent->next_hash != NULL)
77 ent->next_hash->pprev_hash = &ent->next_hash;
79 ent->pprev_hash = &br->hash[hash];
82 static __inline__ void __hash_unlink(struct net_bridge_fdb_entry *ent)
84 *(ent->pprev_hash) = ent->next_hash;
85 if (ent->next_hash != NULL)
86 ent->next_hash->pprev_hash = ent->pprev_hash;
87 ent->next_hash = NULL;
88 ent->pprev_hash = NULL;
93 void br_fdb_changeaddr(struct net_bridge_port *p, unsigned char *newaddr)
95 struct net_bridge *br;
99 write_lock_bh(&br->hash_lock);
100 for (i=0;i<BR_HASH_SIZE;i++) {
101 struct net_bridge_fdb_entry *f;
105 if (f->dst == p && f->is_local) {
107 memcpy(f->addr.addr, newaddr, ETH_ALEN);
108 __hash_link(br, f, br_mac_hash(newaddr));
109 write_unlock_bh(&br->hash_lock);
115 write_unlock_bh(&br->hash_lock);
118 void br_fdb_cleanup(struct net_bridge *br)
121 unsigned long timeout;
123 timeout = __timeout(br);
125 write_lock_bh(&br->hash_lock);
126 for (i=0;i<BR_HASH_SIZE;i++) {
127 struct net_bridge_fdb_entry *f;
131 struct net_bridge_fdb_entry *g;
135 time_before_eq(f->ageing_timer, timeout)) {
142 write_unlock_bh(&br->hash_lock);
145 void br_fdb_delete_by_port(struct net_bridge *br, struct net_bridge_port *p)
149 write_lock_bh(&br->hash_lock);
150 for (i=0;i<BR_HASH_SIZE;i++) {
151 struct net_bridge_fdb_entry *f;
155 struct net_bridge_fdb_entry *g;
165 write_unlock_bh(&br->hash_lock);
168 struct net_bridge_fdb_entry *br_fdb_get(struct net_bridge *br, unsigned char *addr)
170 struct net_bridge_fdb_entry *fdb;
172 read_lock_bh(&br->hash_lock);
173 fdb = br->hash[br_mac_hash(addr)];
174 while (fdb != NULL) {
175 if (!memcmp(fdb->addr.addr, addr, ETH_ALEN)) {
176 if (!has_expired(br, fdb)) {
177 atomic_inc(&fdb->use_count);
178 read_unlock_bh(&br->hash_lock);
182 read_unlock_bh(&br->hash_lock);
186 fdb = fdb->next_hash;
189 read_unlock_bh(&br->hash_lock);
193 void br_fdb_put(struct net_bridge_fdb_entry *ent)
195 if (atomic_dec_and_test(&ent->use_count))
199 int br_fdb_get_entries(struct net_bridge *br,
206 struct __fdb_entry *walk;
209 walk = (struct __fdb_entry *)_buf;
211 read_lock_bh(&br->hash_lock);
212 for (i=0;i<BR_HASH_SIZE;i++) {
213 struct net_bridge_fdb_entry *f;
216 while (f != NULL && num < maxnum) {
217 struct __fdb_entry ent;
219 struct net_bridge_fdb_entry *g;
220 struct net_bridge_fdb_entry **pp;
222 if (has_expired(br, f)) {
235 atomic_inc(&f->use_count);
236 read_unlock_bh(&br->hash_lock);
237 err = copy_to_user(walk, &ent, sizeof(struct __fdb_entry));
238 read_lock_bh(&br->hash_lock);
247 if (g == NULL && pp == NULL)
248 goto out_disappeared;
258 read_unlock_bh(&br->hash_lock);
270 static __inline__ void __fdb_possibly_replace(struct net_bridge_fdb_entry *fdb,
271 struct net_bridge_port *source,
274 if (!fdb->is_static || is_local) {
276 fdb->is_local = is_local;
277 fdb->is_static = is_local;
278 fdb->ageing_timer = jiffies;
282 void br_fdb_insert(struct net_bridge *br,
283 struct net_bridge_port *source,
287 struct net_bridge_fdb_entry *fdb;
290 hash = br_mac_hash(addr);
292 write_lock_bh(&br->hash_lock);
293 fdb = br->hash[hash];
294 while (fdb != NULL) {
295 if (!memcmp(fdb->addr.addr, addr, ETH_ALEN)) {
296 /* attempt to update an entry for a local interface */
299 printk(KERN_INFO "%s: attempt to add"
300 " interface with same source address.\n",
302 else if (net_ratelimit())
303 printk(KERN_WARNING "%s: received packet with "
304 " own address as source address\n",
309 __fdb_possibly_replace(fdb, source, is_local);
313 fdb = fdb->next_hash;
316 fdb = kmalloc(sizeof(*fdb), GFP_ATOMIC);
320 memcpy(fdb->addr.addr, addr, ETH_ALEN);
321 atomic_set(&fdb->use_count, 1);
323 fdb->is_local = is_local;
324 fdb->is_static = is_local;
325 fdb->ageing_timer = jiffies;
327 __hash_link(br, fdb, hash);
330 write_unlock_bh(&br->hash_lock);