OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [net/] [bridge/] [br_fdb.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
2
 *      Forwarding database
3
 *      Linux ethernet bridge
4
 *
5
 *      Authors:
6
 *      Lennert Buytenhek               <buytenh@gnu.org>
7
 *
8
 *      $Id: br_fdb.c,v 1.1.1.1 2004-04-15 01:16:25 phoenix Exp $
9
 *
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.
14
 */
15
 
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"
22
 
23
static __inline__ unsigned long __timeout(struct net_bridge *br)
24
{
25
        unsigned long timeout;
26
 
27
        timeout = jiffies - br->ageing_time;
28
        if (br->topology_change)
29
                timeout = jiffies - br->forward_delay;
30
 
31
        return timeout;
32
}
33
 
34
static __inline__ int has_expired(struct net_bridge *br,
35
                                  struct net_bridge_fdb_entry *fdb)
36
{
37
        if (!fdb->is_static &&
38
            time_before_eq(fdb->ageing_timer, __timeout(br)))
39
                return 1;
40
 
41
        return 0;
42
}
43
 
44
static __inline__ void copy_fdb(struct __fdb_entry *ent, struct net_bridge_fdb_entry *f)
45
{
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;
51
        if (!f->is_static)
52
                ent->ageing_timer_value = jiffies - f->ageing_timer;
53
}
54
 
55
static __inline__ int br_mac_hash(unsigned char *mac)
56
{
57
        unsigned long x;
58
 
59
        x = mac[0];
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];
65
 
66
        x ^= x >> 8;
67
 
68
        return x & (BR_HASH_SIZE - 1);
69
}
70
 
71
static __inline__ void __hash_link(struct net_bridge *br,
72
                                   struct net_bridge_fdb_entry *ent,
73
                                   int hash)
74
{
75
        ent->next_hash = br->hash[hash];
76
        if (ent->next_hash != NULL)
77
                ent->next_hash->pprev_hash = &ent->next_hash;
78
        br->hash[hash] = ent;
79
        ent->pprev_hash = &br->hash[hash];
80
}
81
 
82
static __inline__ void __hash_unlink(struct net_bridge_fdb_entry *ent)
83
{
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;
89
}
90
 
91
 
92
 
93
void br_fdb_changeaddr(struct net_bridge_port *p, unsigned char *newaddr)
94
{
95
        struct net_bridge *br;
96
        int i;
97
 
98
        br = p->br;
99
        write_lock_bh(&br->hash_lock);
100
        for (i=0;i<BR_HASH_SIZE;i++) {
101
                struct net_bridge_fdb_entry *f;
102
 
103
                f = br->hash[i];
104
                while (f != NULL) {
105
                        if (f->dst == p && f->is_local) {
106
                                __hash_unlink(f);
107
                                memcpy(f->addr.addr, newaddr, ETH_ALEN);
108
                                __hash_link(br, f, br_mac_hash(newaddr));
109
                                write_unlock_bh(&br->hash_lock);
110
                                return;
111
                        }
112
                        f = f->next_hash;
113
                }
114
        }
115
        write_unlock_bh(&br->hash_lock);
116
}
117
 
118
void br_fdb_cleanup(struct net_bridge *br)
119
{
120
        int i;
121
        unsigned long timeout;
122
 
123
        timeout = __timeout(br);
124
 
125
        write_lock_bh(&br->hash_lock);
126
        for (i=0;i<BR_HASH_SIZE;i++) {
127
                struct net_bridge_fdb_entry *f;
128
 
129
                f = br->hash[i];
130
                while (f != NULL) {
131
                        struct net_bridge_fdb_entry *g;
132
 
133
                        g = f->next_hash;
134
                        if (!f->is_static &&
135
                            time_before_eq(f->ageing_timer, timeout)) {
136
                                __hash_unlink(f);
137
                                br_fdb_put(f);
138
                        }
139
                        f = g;
140
                }
141
        }
142
        write_unlock_bh(&br->hash_lock);
143
}
144
 
145
void br_fdb_delete_by_port(struct net_bridge *br, struct net_bridge_port *p)
146
{
147
        int i;
148
 
149
        write_lock_bh(&br->hash_lock);
150
        for (i=0;i<BR_HASH_SIZE;i++) {
151
                struct net_bridge_fdb_entry *f;
152
 
153
                f = br->hash[i];
154
                while (f != NULL) {
155
                        struct net_bridge_fdb_entry *g;
156
 
157
                        g = f->next_hash;
158
                        if (f->dst == p) {
159
                                __hash_unlink(f);
160
                                br_fdb_put(f);
161
                        }
162
                        f = g;
163
                }
164
        }
165
        write_unlock_bh(&br->hash_lock);
166
}
167
 
168
struct net_bridge_fdb_entry *br_fdb_get(struct net_bridge *br, unsigned char *addr)
169
{
170
        struct net_bridge_fdb_entry *fdb;
171
 
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);
179
                                return fdb;
180
                        }
181
 
182
                        read_unlock_bh(&br->hash_lock);
183
                        return NULL;
184
                }
185
 
186
                fdb = fdb->next_hash;
187
        }
188
 
189
        read_unlock_bh(&br->hash_lock);
190
        return NULL;
191
}
192
 
193
void br_fdb_put(struct net_bridge_fdb_entry *ent)
194
{
195
        if (atomic_dec_and_test(&ent->use_count))
196
                kfree(ent);
197
}
198
 
199
int br_fdb_get_entries(struct net_bridge *br,
200
                       unsigned char *_buf,
201
                       int maxnum,
202
                       int offset)
203
{
204
        int i;
205
        int num;
206
        struct __fdb_entry *walk;
207
 
208
        num = 0;
209
        walk = (struct __fdb_entry *)_buf;
210
 
211
        read_lock_bh(&br->hash_lock);
212
        for (i=0;i<BR_HASH_SIZE;i++) {
213
                struct net_bridge_fdb_entry *f;
214
 
215
                f = br->hash[i];
216
                while (f != NULL && num < maxnum) {
217
                        struct __fdb_entry ent;
218
                        int err;
219
                        struct net_bridge_fdb_entry *g;
220
                        struct net_bridge_fdb_entry **pp;
221
 
222
                        if (has_expired(br, f)) {
223
                                f = f->next_hash;
224
                                continue;
225
                        }
226
 
227
                        if (offset) {
228
                                offset--;
229
                                f = f->next_hash;
230
                                continue;
231
                        }
232
 
233
                        copy_fdb(&ent, f);
234
 
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);
239
 
240
                        g = f->next_hash;
241
                        pp = f->pprev_hash;
242
                        br_fdb_put(f);
243
 
244
                        if (err)
245
                                goto out_fault;
246
 
247
                        if (g == NULL && pp == NULL)
248
                                goto out_disappeared;
249
 
250
                        num++;
251
                        walk++;
252
 
253
                        f = g;
254
                }
255
        }
256
 
257
 out:
258
        read_unlock_bh(&br->hash_lock);
259
        return num;
260
 
261
 out_disappeared:
262
        num = -EAGAIN;
263
        goto out;
264
 
265
 out_fault:
266
        num = -EFAULT;
267
        goto out;
268
}
269
 
270
static __inline__ void __fdb_possibly_replace(struct net_bridge_fdb_entry *fdb,
271
                                              struct net_bridge_port *source,
272
                                              int is_local)
273
{
274
        if (!fdb->is_static || is_local) {
275
                fdb->dst = source;
276
                fdb->is_local = is_local;
277
                fdb->is_static = is_local;
278
                fdb->ageing_timer = jiffies;
279
        }
280
}
281
 
282
void br_fdb_insert(struct net_bridge *br,
283
                   struct net_bridge_port *source,
284
                   unsigned char *addr,
285
                   int is_local)
286
{
287
        struct net_bridge_fdb_entry *fdb;
288
        int hash;
289
 
290
        hash = br_mac_hash(addr);
291
 
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 */
297
                        if (fdb->is_local) {
298
                                if (is_local)
299
                                        printk(KERN_INFO "%s: attempt to add"
300
                                               " interface with same source address.\n",
301
                                               source->dev->name);
302
                                else if (net_ratelimit())
303
                                        printk(KERN_WARNING "%s: received packet with "
304
                                               " own address as source address\n",
305
                                               source->dev->name);
306
                                goto out;
307
                        }
308
 
309
                        __fdb_possibly_replace(fdb, source, is_local);
310
                        goto out;
311
                }
312
 
313
                fdb = fdb->next_hash;
314
        }
315
 
316
        fdb = kmalloc(sizeof(*fdb), GFP_ATOMIC);
317
        if (fdb == NULL)
318
                goto out;
319
 
320
        memcpy(fdb->addr.addr, addr, ETH_ALEN);
321
        atomic_set(&fdb->use_count, 1);
322
        fdb->dst = source;
323
        fdb->is_local = is_local;
324
        fdb->is_static = is_local;
325
        fdb->ageing_timer = jiffies;
326
 
327
        __hash_link(br, fdb, hash);
328
 
329
 out:
330
        write_unlock_bh(&br->hash_lock);
331
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.