aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/bridge/br_fdb.c61
-rw-r--r--net/bridge/br_if.c2
-rw-r--r--net/bridge/br_private.h10
-rw-r--r--net/bridge/br_vlan.c77
4 files changed, 125 insertions, 25 deletions
diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c
index 4b75ad43aa85..8117900af4de 100644
--- a/net/bridge/br_fdb.c
+++ b/net/bridge/br_fdb.c
@@ -28,7 +28,7 @@
28 28
29static struct kmem_cache *br_fdb_cache __read_mostly; 29static struct kmem_cache *br_fdb_cache __read_mostly;
30static int fdb_insert(struct net_bridge *br, struct net_bridge_port *source, 30static int fdb_insert(struct net_bridge *br, struct net_bridge_port *source,
31 const unsigned char *addr); 31 const unsigned char *addr, u16 vid);
32static void fdb_notify(struct net_bridge *br, 32static void fdb_notify(struct net_bridge *br,
33 const struct net_bridge_fdb_entry *, int); 33 const struct net_bridge_fdb_entry *, int);
34 34
@@ -92,6 +92,7 @@ static void fdb_delete(struct net_bridge *br, struct net_bridge_fdb_entry *f)
92void br_fdb_changeaddr(struct net_bridge_port *p, const unsigned char *newaddr) 92void br_fdb_changeaddr(struct net_bridge_port *p, const unsigned char *newaddr)
93{ 93{
94 struct net_bridge *br = p->br; 94 struct net_bridge *br = p->br;
95 bool no_vlan = (nbp_get_vlan_info(p) == NULL) ? true : false;
95 int i; 96 int i;
96 97
97 spin_lock_bh(&br->hash_lock); 98 spin_lock_bh(&br->hash_lock);
@@ -106,10 +107,12 @@ void br_fdb_changeaddr(struct net_bridge_port *p, const unsigned char *newaddr)
106 if (f->dst == p && f->is_local) { 107 if (f->dst == p && f->is_local) {
107 /* maybe another port has same hw addr? */ 108 /* maybe another port has same hw addr? */
108 struct net_bridge_port *op; 109 struct net_bridge_port *op;
110 u16 vid = f->vlan_id;
109 list_for_each_entry(op, &br->port_list, list) { 111 list_for_each_entry(op, &br->port_list, list) {
110 if (op != p && 112 if (op != p &&
111 ether_addr_equal(op->dev->dev_addr, 113 ether_addr_equal(op->dev->dev_addr,
112 f->addr.addr)) { 114 f->addr.addr) &&
115 nbp_vlan_find(op, vid)) {
113 f->dst = op; 116 f->dst = op;
114 goto insert; 117 goto insert;
115 } 118 }
@@ -117,27 +120,55 @@ void br_fdb_changeaddr(struct net_bridge_port *p, const unsigned char *newaddr)
117 120
118 /* delete old one */ 121 /* delete old one */
119 fdb_delete(br, f); 122 fdb_delete(br, f);
120 goto insert; 123insert:
124 /* insert new address, may fail if invalid
125 * address or dup.
126 */
127 fdb_insert(br, p, newaddr, vid);
128
129 /* if this port has no vlan information
130 * configured, we can safely be done at
131 * this point.
132 */
133 if (no_vlan)
134 goto done;
121 } 135 }
122 } 136 }
123 } 137 }
124 insert:
125 /* insert new address, may fail if invalid address or dup. */
126 fdb_insert(br, p, newaddr);
127 138
139done:
128 spin_unlock_bh(&br->hash_lock); 140 spin_unlock_bh(&br->hash_lock);
129} 141}
130 142
131void br_fdb_change_mac_address(struct net_bridge *br, const u8 *newaddr) 143void br_fdb_change_mac_address(struct net_bridge *br, const u8 *newaddr)
132{ 144{
133 struct net_bridge_fdb_entry *f; 145 struct net_bridge_fdb_entry *f;
146 struct net_port_vlans *pv;
147 u16 vid = 0;
134 148
135 /* If old entry was unassociated with any port, then delete it. */ 149 /* If old entry was unassociated with any port, then delete it. */
136 f = __br_fdb_get(br, br->dev->dev_addr, 0); 150 f = __br_fdb_get(br, br->dev->dev_addr, 0);
137 if (f && f->is_local && !f->dst) 151 if (f && f->is_local && !f->dst)
138 fdb_delete(br, f); 152 fdb_delete(br, f);
139 153
140 fdb_insert(br, NULL, newaddr); 154 fdb_insert(br, NULL, newaddr, 0);
155
156 /* Now remove and add entries for every VLAN configured on the
157 * bridge. This function runs under RTNL so the bitmap will not
158 * change from under us.
159 */
160 pv = br_get_vlan_info(br);
161 if (!pv)
162 return;
163
164 for (vid = find_next_bit(pv->vlan_bitmap, BR_VLAN_BITMAP_LEN, vid);
165 vid < BR_VLAN_BITMAP_LEN;
166 vid = find_next_bit(pv->vlan_bitmap, BR_VLAN_BITMAP_LEN, vid+1)) {
167 f = __br_fdb_get(br, br->dev->dev_addr, vid);
168 if (f && f->is_local && !f->dst)
169 fdb_delete(br, f);
170 fdb_insert(br, NULL, newaddr, vid);
171 }
141} 172}
142 173
143void br_fdb_cleanup(unsigned long _data) 174void br_fdb_cleanup(unsigned long _data)
@@ -379,15 +410,15 @@ static struct net_bridge_fdb_entry *fdb_create(struct hlist_head *head,
379} 410}
380 411
381static int fdb_insert(struct net_bridge *br, struct net_bridge_port *source, 412static int fdb_insert(struct net_bridge *br, struct net_bridge_port *source,
382 const unsigned char *addr) 413 const unsigned char *addr, u16 vid)
383{ 414{
384 struct hlist_head *head = &br->hash[br_mac_hash(addr, 0)]; 415 struct hlist_head *head = &br->hash[br_mac_hash(addr, vid)];
385 struct net_bridge_fdb_entry *fdb; 416 struct net_bridge_fdb_entry *fdb;
386 417
387 if (!is_valid_ether_addr(addr)) 418 if (!is_valid_ether_addr(addr))
388 return -EINVAL; 419 return -EINVAL;
389 420
390 fdb = fdb_find(head, addr, 0); 421 fdb = fdb_find(head, addr, vid);
391 if (fdb) { 422 if (fdb) {
392 /* it is okay to have multiple ports with same 423 /* it is okay to have multiple ports with same
393 * address, just use the first one. 424 * address, just use the first one.
@@ -400,7 +431,7 @@ static int fdb_insert(struct net_bridge *br, struct net_bridge_port *source,
400 fdb_delete(br, fdb); 431 fdb_delete(br, fdb);
401 } 432 }
402 433
403 fdb = fdb_create(head, source, addr, 0); 434 fdb = fdb_create(head, source, addr, vid);
404 if (!fdb) 435 if (!fdb)
405 return -ENOMEM; 436 return -ENOMEM;
406 437
@@ -411,12 +442,12 @@ static int fdb_insert(struct net_bridge *br, struct net_bridge_port *source,
411 442
412/* Add entry for local address of interface */ 443/* Add entry for local address of interface */
413int br_fdb_insert(struct net_bridge *br, struct net_bridge_port *source, 444int br_fdb_insert(struct net_bridge *br, struct net_bridge_port *source,
414 const unsigned char *addr) 445 const unsigned char *addr, u16 vid)
415{ 446{
416 int ret; 447 int ret;
417 448
418 spin_lock_bh(&br->hash_lock); 449 spin_lock_bh(&br->hash_lock);
419 ret = fdb_insert(br, source, addr); 450 ret = fdb_insert(br, source, addr, vid);
420 spin_unlock_bh(&br->hash_lock); 451 spin_unlock_bh(&br->hash_lock);
421 return ret; 452 return ret;
422} 453}
@@ -712,8 +743,8 @@ out:
712 return err; 743 return err;
713} 744}
714 745
715static int fdb_delete_by_addr(struct net_bridge *br, const u8 *addr, 746int fdb_delete_by_addr(struct net_bridge *br, const u8 *addr,
716 u16 vlan) 747 u16 vlan)
717{ 748{
718 struct hlist_head *head = &br->hash[br_mac_hash(addr, vlan)]; 749 struct hlist_head *head = &br->hash[br_mac_hash(addr, vlan)];
719 struct net_bridge_fdb_entry *fdb; 750 struct net_bridge_fdb_entry *fdb;
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c
index 335c60cebfd1..ef1b91431c6b 100644
--- a/net/bridge/br_if.c
+++ b/net/bridge/br_if.c
@@ -397,7 +397,7 @@ int br_add_if(struct net_bridge *br, struct net_device *dev)
397 397
398 dev_set_mtu(br->dev, br_min_mtu(br)); 398 dev_set_mtu(br->dev, br_min_mtu(br));
399 399
400 if (br_fdb_insert(br, p, dev->dev_addr)) 400 if (br_fdb_insert(br, p, dev->dev_addr, 0))
401 netdev_err(dev, "failed insert local address bridge forwarding table\n"); 401 netdev_err(dev, "failed insert local address bridge forwarding table\n");
402 402
403 kobject_uevent(&p->kobj, KOBJ_ADD); 403 kobject_uevent(&p->kobj, KOBJ_ADD);
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index 799dbb37e5a2..32ecfa4ef47f 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -382,11 +382,13 @@ extern int br_fdb_fillbuf(struct net_bridge *br, void *buf,
382 unsigned long count, unsigned long off); 382 unsigned long count, unsigned long off);
383extern int br_fdb_insert(struct net_bridge *br, 383extern int br_fdb_insert(struct net_bridge *br,
384 struct net_bridge_port *source, 384 struct net_bridge_port *source,
385 const unsigned char *addr); 385 const unsigned char *addr,
386 u16 vid);
386extern void br_fdb_update(struct net_bridge *br, 387extern void br_fdb_update(struct net_bridge *br,
387 struct net_bridge_port *source, 388 struct net_bridge_port *source,
388 const unsigned char *addr, 389 const unsigned char *addr,
389 u16 vid); 390 u16 vid);
391extern int fdb_delete_by_addr(struct net_bridge *br, const u8 *addr, u16 vid);
390 392
391extern int br_fdb_delete(struct ndmsg *ndm, struct nlattr *tb[], 393extern int br_fdb_delete(struct ndmsg *ndm, struct nlattr *tb[],
392 struct net_device *dev, 394 struct net_device *dev,
@@ -573,6 +575,7 @@ extern int br_vlan_filter_toggle(struct net_bridge *br, unsigned long val);
573extern int nbp_vlan_add(struct net_bridge_port *port, u16 vid, u16 flags); 575extern int nbp_vlan_add(struct net_bridge_port *port, u16 vid, u16 flags);
574extern int nbp_vlan_delete(struct net_bridge_port *port, u16 vid); 576extern int nbp_vlan_delete(struct net_bridge_port *port, u16 vid);
575extern void nbp_vlan_flush(struct net_bridge_port *port); 577extern void nbp_vlan_flush(struct net_bridge_port *port);
578extern bool nbp_vlan_find(struct net_bridge_port *port, u16 vid);
576 579
577static inline struct net_port_vlans *br_get_vlan_info( 580static inline struct net_port_vlans *br_get_vlan_info(
578 const struct net_bridge *br) 581 const struct net_bridge *br)
@@ -676,6 +679,11 @@ static inline struct net_port_vlans *nbp_get_vlan_info(
676 return NULL; 679 return NULL;
677} 680}
678 681
682static inline bool nbp_vlan_find(struct net_bridge_port *port, u16 vid)
683{
684 return false;
685}
686
679static inline u16 br_vlan_get_tag(const struct sk_buff *skb, u16 *tag) 687static inline u16 br_vlan_get_tag(const struct sk_buff *skb, u16 *tag)
680{ 688{
681 return 0; 689 return 0;
diff --git a/net/bridge/br_vlan.c b/net/bridge/br_vlan.c
index c79940cff3a1..9ea358fbbf78 100644
--- a/net/bridge/br_vlan.c
+++ b/net/bridge/br_vlan.c
@@ -25,6 +25,9 @@ static void __vlan_delete_pvid(struct net_port_vlans *v, u16 vid)
25 25
26static int __vlan_add(struct net_port_vlans *v, u16 vid, u16 flags) 26static int __vlan_add(struct net_port_vlans *v, u16 vid, u16 flags)
27{ 27{
28 struct net_bridge_port *p = NULL;
29 struct net_bridge *br;
30 struct net_device *dev;
28 int err; 31 int err;
29 32
30 if (test_bit(vid, v->vlan_bitmap)) { 33 if (test_bit(vid, v->vlan_bitmap)) {
@@ -33,19 +36,35 @@ static int __vlan_add(struct net_port_vlans *v, u16 vid, u16 flags)
33 return 0; 36 return 0;
34 } 37 }
35 38
36 if (v->port_idx && vid) { 39 if (vid) {
37 struct net_device *dev = v->parent.port->dev; 40 if (v->port_idx) {
41 p = v->parent.port;
42 br = p->br;
43 dev = p->dev;
44 } else {
45 br = v->parent.br;
46 dev = br->dev;
47 }
38 48
39 /* Add VLAN to the device filter if it is supported. 49 if (p && (dev->features & NETIF_F_HW_VLAN_FILTER)) {
40 * Stricly speaking, this is not necessary now, since devices 50 /* Add VLAN to the device filter if it is supported.
41 * are made promiscuous by the bridge, but if that ever changes 51 * Stricly speaking, this is not necessary now, since
42 * this code will allow tagged traffic to enter the bridge. 52 * devices are made promiscuous by the bridge, but if
43 */ 53 * that ever changes this code will allow tagged
44 if (dev->features & NETIF_F_HW_VLAN_FILTER) { 54 * traffic to enter the bridge.
55 */
45 err = dev->netdev_ops->ndo_vlan_rx_add_vid(dev, vid); 56 err = dev->netdev_ops->ndo_vlan_rx_add_vid(dev, vid);
46 if (err) 57 if (err)
47 return err; 58 return err;
48 } 59 }
60
61 err = br_fdb_insert(br, p, dev->dev_addr, vid);
62 if (err) {
63 br_err(br, "failed insert local address into bridge "
64 "forwarding table\n");
65 goto out_filt;
66 }
67
49 } 68 }
50 69
51 set_bit(vid, v->vlan_bitmap); 70 set_bit(vid, v->vlan_bitmap);
@@ -54,6 +73,11 @@ static int __vlan_add(struct net_port_vlans *v, u16 vid, u16 flags)
54 __vlan_add_pvid(v, vid); 73 __vlan_add_pvid(v, vid);
55 74
56 return 0; 75 return 0;
76
77out_filt:
78 if (p && (dev->features & NETIF_F_HW_VLAN_FILTER))
79 dev->netdev_ops->ndo_vlan_rx_kill_vid(dev, vid);
80 return err;
57} 81}
58 82
59static int __vlan_del(struct net_port_vlans *v, u16 vid) 83static int __vlan_del(struct net_port_vlans *v, u16 vid)
@@ -253,6 +277,15 @@ int br_vlan_delete(struct net_bridge *br, u16 vid)
253 if (!pv) 277 if (!pv)
254 return -EINVAL; 278 return -EINVAL;
255 279
280 if (vid) {
281 /* If the VID !=0 remove fdb for this vid. VID 0 is special
282 * in that it's the default and is always there in the fdb.
283 */
284 spin_lock_bh(&br->hash_lock);
285 fdb_delete_by_addr(br, br->dev->dev_addr, vid);
286 spin_unlock_bh(&br->hash_lock);
287 }
288
256 __vlan_del(pv, vid); 289 __vlan_del(pv, vid);
257 return 0; 290 return 0;
258} 291}
@@ -329,6 +362,15 @@ int nbp_vlan_delete(struct net_bridge_port *port, u16 vid)
329 if (!pv) 362 if (!pv)
330 return -EINVAL; 363 return -EINVAL;
331 364
365 if (vid) {
366 /* If the VID !=0 remove fdb for this vid. VID 0 is special
367 * in that it's the default and is always there in the fdb.
368 */
369 spin_lock_bh(&port->br->hash_lock);
370 fdb_delete_by_addr(port->br, port->dev->dev_addr, vid);
371 spin_unlock_bh(&port->br->hash_lock);
372 }
373
332 return __vlan_del(pv, vid); 374 return __vlan_del(pv, vid);
333} 375}
334 376
@@ -344,3 +386,22 @@ void nbp_vlan_flush(struct net_bridge_port *port)
344 386
345 __vlan_flush(pv); 387 __vlan_flush(pv);
346} 388}
389
390bool nbp_vlan_find(struct net_bridge_port *port, u16 vid)
391{
392 struct net_port_vlans *pv;
393 bool found = false;
394
395 rcu_read_lock();
396 pv = rcu_dereference(port->vlan_info);
397
398 if (!pv)
399 goto out;
400
401 if (test_bit(vid, pv->vlan_bitmap))
402 found = true;
403
404out:
405 rcu_read_unlock();
406 return found;
407}