aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/bridge/br_device.c2
-rw-r--r--net/bridge/br_fdb.c69
-rw-r--r--net/bridge/br_input.c9
-rw-r--r--net/bridge/br_private.h7
4 files changed, 52 insertions, 35 deletions
diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c
index 9509139da49c..d5f1d3fd4b28 100644
--- a/net/bridge/br_device.c
+++ b/net/bridge/br_device.c
@@ -71,7 +71,7 @@ netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev)
71 br_multicast_deliver(mdst, skb); 71 br_multicast_deliver(mdst, skb);
72 else 72 else
73 br_flood_deliver(br, skb); 73 br_flood_deliver(br, skb);
74 } else if ((dst = __br_fdb_get(br, dest)) != NULL) 74 } else if ((dst = __br_fdb_get(br, dest, vid)) != NULL)
75 br_deliver(dst->dst, skb); 75 br_deliver(dst->dst, skb);
76 else 76 else
77 br_flood_deliver(br, skb); 77 br_flood_deliver(br, skb);
diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c
index d9576e6de2b8..276a52254606 100644
--- a/net/bridge/br_fdb.c
+++ b/net/bridge/br_fdb.c
@@ -23,6 +23,7 @@
23#include <linux/slab.h> 23#include <linux/slab.h>
24#include <linux/atomic.h> 24#include <linux/atomic.h>
25#include <asm/unaligned.h> 25#include <asm/unaligned.h>
26#include <linux/if_vlan.h>
26#include "br_private.h" 27#include "br_private.h"
27 28
28static struct kmem_cache *br_fdb_cache __read_mostly; 29static struct kmem_cache *br_fdb_cache __read_mostly;
@@ -67,11 +68,11 @@ static inline int has_expired(const struct net_bridge *br,
67 time_before_eq(fdb->updated + hold_time(br), jiffies); 68 time_before_eq(fdb->updated + hold_time(br), jiffies);
68} 69}
69 70
70static inline int br_mac_hash(const unsigned char *mac) 71static inline int br_mac_hash(const unsigned char *mac, __u16 vid)
71{ 72{
72 /* use 1 byte of OUI cnd 3 bytes of NIC */ 73 /* use 1 byte of OUI and 3 bytes of NIC */
73 u32 key = get_unaligned((u32 *)(mac + 2)); 74 u32 key = get_unaligned((u32 *)(mac + 2));
74 return jhash_1word(key, fdb_salt) & (BR_HASH_SIZE - 1); 75 return jhash_2words(key, vid, fdb_salt) & (BR_HASH_SIZE - 1);
75} 76}
76 77
77static void fdb_rcu_free(struct rcu_head *head) 78static void fdb_rcu_free(struct rcu_head *head)
@@ -132,7 +133,7 @@ void br_fdb_change_mac_address(struct net_bridge *br, const u8 *newaddr)
132 struct net_bridge_fdb_entry *f; 133 struct net_bridge_fdb_entry *f;
133 134
134 /* If old entry was unassociated with any port, then delete it. */ 135 /* If old entry was unassociated with any port, then delete it. */
135 f = __br_fdb_get(br, br->dev->dev_addr); 136 f = __br_fdb_get(br, br->dev->dev_addr, 0);
136 if (f && f->is_local && !f->dst) 137 if (f && f->is_local && !f->dst)
137 fdb_delete(br, f); 138 fdb_delete(br, f);
138 139
@@ -231,13 +232,16 @@ void br_fdb_delete_by_port(struct net_bridge *br,
231 232
232/* No locking or refcounting, assumes caller has rcu_read_lock */ 233/* No locking or refcounting, assumes caller has rcu_read_lock */
233struct net_bridge_fdb_entry *__br_fdb_get(struct net_bridge *br, 234struct net_bridge_fdb_entry *__br_fdb_get(struct net_bridge *br,
234 const unsigned char *addr) 235 const unsigned char *addr,
236 __u16 vid)
235{ 237{
236 struct hlist_node *h; 238 struct hlist_node *h;
237 struct net_bridge_fdb_entry *fdb; 239 struct net_bridge_fdb_entry *fdb;
238 240
239 hlist_for_each_entry_rcu(fdb, h, &br->hash[br_mac_hash(addr)], hlist) { 241 hlist_for_each_entry_rcu(fdb, h,
240 if (ether_addr_equal(fdb->addr.addr, addr)) { 242 &br->hash[br_mac_hash(addr, vid)], hlist) {
243 if (ether_addr_equal(fdb->addr.addr, addr) &&
244 fdb->vlan_id == vid) {
241 if (unlikely(has_expired(br, fdb))) 245 if (unlikely(has_expired(br, fdb)))
242 break; 246 break;
243 return fdb; 247 return fdb;
@@ -261,7 +265,7 @@ int br_fdb_test_addr(struct net_device *dev, unsigned char *addr)
261 if (!port) 265 if (!port)
262 ret = 0; 266 ret = 0;
263 else { 267 else {
264 fdb = __br_fdb_get(port->br, addr); 268 fdb = __br_fdb_get(port->br, addr, 0);
265 ret = fdb && fdb->dst && fdb->dst->dev != dev && 269 ret = fdb && fdb->dst && fdb->dst->dev != dev &&
266 fdb->dst->state == BR_STATE_FORWARDING; 270 fdb->dst->state == BR_STATE_FORWARDING;
267 } 271 }
@@ -325,26 +329,30 @@ int br_fdb_fillbuf(struct net_bridge *br, void *buf,
325} 329}
326 330
327static struct net_bridge_fdb_entry *fdb_find(struct hlist_head *head, 331static struct net_bridge_fdb_entry *fdb_find(struct hlist_head *head,
328 const unsigned char *addr) 332 const unsigned char *addr,
333 __u16 vid)
329{ 334{
330 struct hlist_node *h; 335 struct hlist_node *h;
331 struct net_bridge_fdb_entry *fdb; 336 struct net_bridge_fdb_entry *fdb;
332 337
333 hlist_for_each_entry(fdb, h, head, hlist) { 338 hlist_for_each_entry(fdb, h, head, hlist) {
334 if (ether_addr_equal(fdb->addr.addr, addr)) 339 if (ether_addr_equal(fdb->addr.addr, addr) &&
340 fdb->vlan_id == vid)
335 return fdb; 341 return fdb;
336 } 342 }
337 return NULL; 343 return NULL;
338} 344}
339 345
340static struct net_bridge_fdb_entry *fdb_find_rcu(struct hlist_head *head, 346static struct net_bridge_fdb_entry *fdb_find_rcu(struct hlist_head *head,
341 const unsigned char *addr) 347 const unsigned char *addr,
348 __u16 vid)
342{ 349{
343 struct hlist_node *h; 350 struct hlist_node *h;
344 struct net_bridge_fdb_entry *fdb; 351 struct net_bridge_fdb_entry *fdb;
345 352
346 hlist_for_each_entry_rcu(fdb, h, head, hlist) { 353 hlist_for_each_entry_rcu(fdb, h, head, hlist) {
347 if (ether_addr_equal(fdb->addr.addr, addr)) 354 if (ether_addr_equal(fdb->addr.addr, addr) &&
355 fdb->vlan_id == vid)
348 return fdb; 356 return fdb;
349 } 357 }
350 return NULL; 358 return NULL;
@@ -352,7 +360,8 @@ static struct net_bridge_fdb_entry *fdb_find_rcu(struct hlist_head *head,
352 360
353static struct net_bridge_fdb_entry *fdb_create(struct hlist_head *head, 361static struct net_bridge_fdb_entry *fdb_create(struct hlist_head *head,
354 struct net_bridge_port *source, 362 struct net_bridge_port *source,
355 const unsigned char *addr) 363 const unsigned char *addr,
364 __u16 vid)
356{ 365{
357 struct net_bridge_fdb_entry *fdb; 366 struct net_bridge_fdb_entry *fdb;
358 367
@@ -360,6 +369,7 @@ static struct net_bridge_fdb_entry *fdb_create(struct hlist_head *head,
360 if (fdb) { 369 if (fdb) {
361 memcpy(fdb->addr.addr, addr, ETH_ALEN); 370 memcpy(fdb->addr.addr, addr, ETH_ALEN);
362 fdb->dst = source; 371 fdb->dst = source;
372 fdb->vlan_id = vid;
363 fdb->is_local = 0; 373 fdb->is_local = 0;
364 fdb->is_static = 0; 374 fdb->is_static = 0;
365 fdb->updated = fdb->used = jiffies; 375 fdb->updated = fdb->used = jiffies;
@@ -371,13 +381,13 @@ static struct net_bridge_fdb_entry *fdb_create(struct hlist_head *head,
371static int fdb_insert(struct net_bridge *br, struct net_bridge_port *source, 381static int fdb_insert(struct net_bridge *br, struct net_bridge_port *source,
372 const unsigned char *addr) 382 const unsigned char *addr)
373{ 383{
374 struct hlist_head *head = &br->hash[br_mac_hash(addr)]; 384 struct hlist_head *head = &br->hash[br_mac_hash(addr, 0)];
375 struct net_bridge_fdb_entry *fdb; 385 struct net_bridge_fdb_entry *fdb;
376 386
377 if (!is_valid_ether_addr(addr)) 387 if (!is_valid_ether_addr(addr))
378 return -EINVAL; 388 return -EINVAL;
379 389
380 fdb = fdb_find(head, addr); 390 fdb = fdb_find(head, addr, 0);
381 if (fdb) { 391 if (fdb) {
382 /* it is okay to have multiple ports with same 392 /* it is okay to have multiple ports with same
383 * address, just use the first one. 393 * address, just use the first one.
@@ -390,7 +400,7 @@ static int fdb_insert(struct net_bridge *br, struct net_bridge_port *source,
390 fdb_delete(br, fdb); 400 fdb_delete(br, fdb);
391 } 401 }
392 402
393 fdb = fdb_create(head, source, addr); 403 fdb = fdb_create(head, source, addr, 0);
394 if (!fdb) 404 if (!fdb)
395 return -ENOMEM; 405 return -ENOMEM;
396 406
@@ -412,9 +422,9 @@ int br_fdb_insert(struct net_bridge *br, struct net_bridge_port *source,
412} 422}
413 423
414void br_fdb_update(struct net_bridge *br, struct net_bridge_port *source, 424void br_fdb_update(struct net_bridge *br, struct net_bridge_port *source,
415 const unsigned char *addr) 425 const unsigned char *addr, u16 vid)
416{ 426{
417 struct hlist_head *head = &br->hash[br_mac_hash(addr)]; 427 struct hlist_head *head = &br->hash[br_mac_hash(addr, vid)];
418 struct net_bridge_fdb_entry *fdb; 428 struct net_bridge_fdb_entry *fdb;
419 429
420 /* some users want to always flood. */ 430 /* some users want to always flood. */
@@ -426,7 +436,7 @@ void br_fdb_update(struct net_bridge *br, struct net_bridge_port *source,
426 source->state == BR_STATE_FORWARDING)) 436 source->state == BR_STATE_FORWARDING))
427 return; 437 return;
428 438
429 fdb = fdb_find_rcu(head, addr); 439 fdb = fdb_find_rcu(head, addr, vid);
430 if (likely(fdb)) { 440 if (likely(fdb)) {
431 /* attempt to update an entry for a local interface */ 441 /* attempt to update an entry for a local interface */
432 if (unlikely(fdb->is_local)) { 442 if (unlikely(fdb->is_local)) {
@@ -441,8 +451,8 @@ void br_fdb_update(struct net_bridge *br, struct net_bridge_port *source,
441 } 451 }
442 } else { 452 } else {
443 spin_lock(&br->hash_lock); 453 spin_lock(&br->hash_lock);
444 if (likely(!fdb_find(head, addr))) { 454 if (likely(!fdb_find(head, addr, vid))) {
445 fdb = fdb_create(head, source, addr); 455 fdb = fdb_create(head, source, addr, vid);
446 if (fdb) 456 if (fdb)
447 fdb_notify(br, fdb, RTM_NEWNEIGH); 457 fdb_notify(br, fdb, RTM_NEWNEIGH);
448 } 458 }
@@ -571,18 +581,18 @@ out:
571 581
572/* Update (create or replace) forwarding database entry */ 582/* Update (create or replace) forwarding database entry */
573static int fdb_add_entry(struct net_bridge_port *source, const __u8 *addr, 583static int fdb_add_entry(struct net_bridge_port *source, const __u8 *addr,
574 __u16 state, __u16 flags) 584 __u16 state, __u16 flags, __u16 vid)
575{ 585{
576 struct net_bridge *br = source->br; 586 struct net_bridge *br = source->br;
577 struct hlist_head *head = &br->hash[br_mac_hash(addr)]; 587 struct hlist_head *head = &br->hash[br_mac_hash(addr, vid)];
578 struct net_bridge_fdb_entry *fdb; 588 struct net_bridge_fdb_entry *fdb;
579 589
580 fdb = fdb_find(head, addr); 590 fdb = fdb_find(head, addr, vid);
581 if (fdb == NULL) { 591 if (fdb == NULL) {
582 if (!(flags & NLM_F_CREATE)) 592 if (!(flags & NLM_F_CREATE))
583 return -ENOENT; 593 return -ENOENT;
584 594
585 fdb = fdb_create(head, source, addr); 595 fdb = fdb_create(head, source, addr, vid);
586 if (!fdb) 596 if (!fdb)
587 return -ENOMEM; 597 return -ENOMEM;
588 fdb_notify(br, fdb, RTM_NEWNEIGH); 598 fdb_notify(br, fdb, RTM_NEWNEIGH);
@@ -629,11 +639,12 @@ int br_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
629 639
630 if (ndm->ndm_flags & NTF_USE) { 640 if (ndm->ndm_flags & NTF_USE) {
631 rcu_read_lock(); 641 rcu_read_lock();
632 br_fdb_update(p->br, p, addr); 642 br_fdb_update(p->br, p, addr, 0);
633 rcu_read_unlock(); 643 rcu_read_unlock();
634 } else { 644 } else {
635 spin_lock_bh(&p->br->hash_lock); 645 spin_lock_bh(&p->br->hash_lock);
636 err = fdb_add_entry(p, addr, ndm->ndm_state, nlh_flags); 646 err = fdb_add_entry(p, addr, ndm->ndm_state, nlh_flags,
647 0);
637 spin_unlock_bh(&p->br->hash_lock); 648 spin_unlock_bh(&p->br->hash_lock);
638 } 649 }
639 650
@@ -643,10 +654,10 @@ int br_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
643static int fdb_delete_by_addr(struct net_bridge_port *p, const u8 *addr) 654static int fdb_delete_by_addr(struct net_bridge_port *p, const u8 *addr)
644{ 655{
645 struct net_bridge *br = p->br; 656 struct net_bridge *br = p->br;
646 struct hlist_head *head = &br->hash[br_mac_hash(addr)]; 657 struct hlist_head *head = &br->hash[br_mac_hash(addr, 0)];
647 struct net_bridge_fdb_entry *fdb; 658 struct net_bridge_fdb_entry *fdb;
648 659
649 fdb = fdb_find(head, addr); 660 fdb = fdb_find(head, addr, 0);
650 if (!fdb) 661 if (!fdb)
651 return -ENOENT; 662 return -ENOENT;
652 663
diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c
index a63f227ad963..480330151898 100644
--- a/net/bridge/br_input.c
+++ b/net/bridge/br_input.c
@@ -75,7 +75,7 @@ int br_handle_frame_finish(struct sk_buff *skb)
75 75
76 /* insert into forwarding database after filtering to avoid spoofing */ 76 /* insert into forwarding database after filtering to avoid spoofing */
77 br = p->br; 77 br = p->br;
78 br_fdb_update(br, p, eth_hdr(skb)->h_source); 78 br_fdb_update(br, p, eth_hdr(skb)->h_source, vid);
79 79
80 if (!is_broadcast_ether_addr(dest) && is_multicast_ether_addr(dest) && 80 if (!is_broadcast_ether_addr(dest) && is_multicast_ether_addr(dest) &&
81 br_multicast_rcv(br, p, skb)) 81 br_multicast_rcv(br, p, skb))
@@ -110,7 +110,8 @@ int br_handle_frame_finish(struct sk_buff *skb)
110 skb2 = skb; 110 skb2 = skb;
111 111
112 br->dev->stats.multicast++; 112 br->dev->stats.multicast++;
113 } else if ((dst = __br_fdb_get(br, dest)) && dst->is_local) { 113 } else if ((dst = __br_fdb_get(br, dest, vid)) &&
114 dst->is_local) {
114 skb2 = skb; 115 skb2 = skb;
115 /* Do not forward the packet since it's local. */ 116 /* Do not forward the packet since it's local. */
116 skb = NULL; 117 skb = NULL;
@@ -138,8 +139,10 @@ drop:
138static int br_handle_local_finish(struct sk_buff *skb) 139static int br_handle_local_finish(struct sk_buff *skb)
139{ 140{
140 struct net_bridge_port *p = br_port_get_rcu(skb->dev); 141 struct net_bridge_port *p = br_port_get_rcu(skb->dev);
142 u16 vid = 0;
141 143
142 br_fdb_update(p->br, p, eth_hdr(skb)->h_source); 144 br_vlan_get_tag(skb, &vid);
145 br_fdb_update(p->br, p, eth_hdr(skb)->h_source, vid);
143 return 0; /* process further */ 146 return 0; /* process further */
144} 147}
145 148
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index 1ae6395a0369..f4ae87b5aa6e 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -88,6 +88,7 @@ struct net_bridge_fdb_entry
88 mac_addr addr; 88 mac_addr addr;
89 unsigned char is_local; 89 unsigned char is_local;
90 unsigned char is_static; 90 unsigned char is_static;
91 __u16 vlan_id;
91}; 92};
92 93
93struct net_bridge_port_group { 94struct net_bridge_port_group {
@@ -373,7 +374,8 @@ extern void br_fdb_cleanup(unsigned long arg);
373extern void br_fdb_delete_by_port(struct net_bridge *br, 374extern void br_fdb_delete_by_port(struct net_bridge *br,
374 const struct net_bridge_port *p, int do_all); 375 const struct net_bridge_port *p, int do_all);
375extern struct net_bridge_fdb_entry *__br_fdb_get(struct net_bridge *br, 376extern struct net_bridge_fdb_entry *__br_fdb_get(struct net_bridge *br,
376 const unsigned char *addr); 377 const unsigned char *addr,
378 __u16 vid);
377extern int br_fdb_test_addr(struct net_device *dev, unsigned char *addr); 379extern int br_fdb_test_addr(struct net_device *dev, unsigned char *addr);
378extern int br_fdb_fillbuf(struct net_bridge *br, void *buf, 380extern int br_fdb_fillbuf(struct net_bridge *br, void *buf,
379 unsigned long count, unsigned long off); 381 unsigned long count, unsigned long off);
@@ -382,7 +384,8 @@ extern int br_fdb_insert(struct net_bridge *br,
382 const unsigned char *addr); 384 const unsigned char *addr);
383extern void br_fdb_update(struct net_bridge *br, 385extern void br_fdb_update(struct net_bridge *br,
384 struct net_bridge_port *source, 386 struct net_bridge_port *source,
385 const unsigned char *addr); 387 const unsigned char *addr,
388 u16 vid);
386 389
387extern int br_fdb_delete(struct ndmsg *ndm, 390extern int br_fdb_delete(struct ndmsg *ndm,
388 struct net_device *dev, 391 struct net_device *dev,