aboutsummaryrefslogtreecommitdiffstats
path: root/net/bridge/br_fdb.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/bridge/br_fdb.c')
-rw-r--r--net/bridge/br_fdb.c61
1 files changed, 46 insertions, 15 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;