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.c137
1 files changed, 89 insertions, 48 deletions
diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c
index c5f5a4a933f4..9203d5a1943f 100644
--- a/net/bridge/br_fdb.c
+++ b/net/bridge/br_fdb.c
@@ -27,6 +27,9 @@
27#include "br_private.h" 27#include "br_private.h"
28 28
29static struct kmem_cache *br_fdb_cache __read_mostly; 29static struct kmem_cache *br_fdb_cache __read_mostly;
30static struct net_bridge_fdb_entry *fdb_find(struct hlist_head *head,
31 const unsigned char *addr,
32 __u16 vid);
30static int fdb_insert(struct net_bridge *br, struct net_bridge_port *source, 33static int fdb_insert(struct net_bridge *br, struct net_bridge_port *source,
31 const unsigned char *addr, u16 vid); 34 const unsigned char *addr, u16 vid);
32static void fdb_notify(struct net_bridge *br, 35static void fdb_notify(struct net_bridge *br,
@@ -89,11 +92,57 @@ static void fdb_delete(struct net_bridge *br, struct net_bridge_fdb_entry *f)
89 call_rcu(&f->rcu, fdb_rcu_free); 92 call_rcu(&f->rcu, fdb_rcu_free);
90} 93}
91 94
95/* Delete a local entry if no other port had the same address. */
96static void fdb_delete_local(struct net_bridge *br,
97 const struct net_bridge_port *p,
98 struct net_bridge_fdb_entry *f)
99{
100 const unsigned char *addr = f->addr.addr;
101 u16 vid = f->vlan_id;
102 struct net_bridge_port *op;
103
104 /* Maybe another port has same hw addr? */
105 list_for_each_entry(op, &br->port_list, list) {
106 if (op != p && ether_addr_equal(op->dev->dev_addr, addr) &&
107 (!vid || nbp_vlan_find(op, vid))) {
108 f->dst = op;
109 f->added_by_user = 0;
110 return;
111 }
112 }
113
114 /* Maybe bridge device has same hw addr? */
115 if (p && ether_addr_equal(br->dev->dev_addr, addr) &&
116 (!vid || br_vlan_find(br, vid))) {
117 f->dst = NULL;
118 f->added_by_user = 0;
119 return;
120 }
121
122 fdb_delete(br, f);
123}
124
125void br_fdb_find_delete_local(struct net_bridge *br,
126 const struct net_bridge_port *p,
127 const unsigned char *addr, u16 vid)
128{
129 struct hlist_head *head = &br->hash[br_mac_hash(addr, vid)];
130 struct net_bridge_fdb_entry *f;
131
132 spin_lock_bh(&br->hash_lock);
133 f = fdb_find(head, addr, vid);
134 if (f && f->is_local && !f->added_by_user && f->dst == p)
135 fdb_delete_local(br, p, f);
136 spin_unlock_bh(&br->hash_lock);
137}
138
92void br_fdb_changeaddr(struct net_bridge_port *p, const unsigned char *newaddr) 139void br_fdb_changeaddr(struct net_bridge_port *p, const unsigned char *newaddr)
93{ 140{
94 struct net_bridge *br = p->br; 141 struct net_bridge *br = p->br;
95 bool no_vlan = (nbp_get_vlan_info(p) == NULL) ? true : false; 142 struct net_port_vlans *pv = nbp_get_vlan_info(p);
143 bool no_vlan = !pv;
96 int i; 144 int i;
145 u16 vid;
97 146
98 spin_lock_bh(&br->hash_lock); 147 spin_lock_bh(&br->hash_lock);
99 148
@@ -104,38 +153,34 @@ void br_fdb_changeaddr(struct net_bridge_port *p, const unsigned char *newaddr)
104 struct net_bridge_fdb_entry *f; 153 struct net_bridge_fdb_entry *f;
105 154
106 f = hlist_entry(h, struct net_bridge_fdb_entry, hlist); 155 f = hlist_entry(h, struct net_bridge_fdb_entry, hlist);
107 if (f->dst == p && f->is_local) { 156 if (f->dst == p && f->is_local && !f->added_by_user) {
108 /* maybe another port has same hw addr? */
109 struct net_bridge_port *op;
110 u16 vid = f->vlan_id;
111 list_for_each_entry(op, &br->port_list, list) {
112 if (op != p &&
113 ether_addr_equal(op->dev->dev_addr,
114 f->addr.addr) &&
115 nbp_vlan_find(op, vid)) {
116 f->dst = op;
117 goto insert;
118 }
119 }
120
121 /* delete old one */ 157 /* delete old one */
122 fdb_delete(br, f); 158 fdb_delete_local(br, p, f);
123insert:
124 /* insert new address, may fail if invalid
125 * address or dup.
126 */
127 fdb_insert(br, p, newaddr, vid);
128 159
129 /* if this port has no vlan information 160 /* if this port has no vlan information
130 * configured, we can safely be done at 161 * configured, we can safely be done at
131 * this point. 162 * this point.
132 */ 163 */
133 if (no_vlan) 164 if (no_vlan)
134 goto done; 165 goto insert;
135 } 166 }
136 } 167 }
137 } 168 }
138 169
170insert:
171 /* insert new address, may fail if invalid address or dup. */
172 fdb_insert(br, p, newaddr, 0);
173
174 if (no_vlan)
175 goto done;
176
177 /* Now add entries for every VLAN configured on the port.
178 * This function runs under RTNL so the bitmap will not change
179 * from under us.
180 */
181 for_each_set_bit(vid, pv->vlan_bitmap, VLAN_N_VID)
182 fdb_insert(br, p, newaddr, vid);
183
139done: 184done:
140 spin_unlock_bh(&br->hash_lock); 185 spin_unlock_bh(&br->hash_lock);
141} 186}
@@ -146,10 +191,12 @@ void br_fdb_change_mac_address(struct net_bridge *br, const u8 *newaddr)
146 struct net_port_vlans *pv; 191 struct net_port_vlans *pv;
147 u16 vid = 0; 192 u16 vid = 0;
148 193
194 spin_lock_bh(&br->hash_lock);
195
149 /* If old entry was unassociated with any port, then delete it. */ 196 /* If old entry was unassociated with any port, then delete it. */
150 f = __br_fdb_get(br, br->dev->dev_addr, 0); 197 f = __br_fdb_get(br, br->dev->dev_addr, 0);
151 if (f && f->is_local && !f->dst) 198 if (f && f->is_local && !f->dst)
152 fdb_delete(br, f); 199 fdb_delete_local(br, NULL, f);
153 200
154 fdb_insert(br, NULL, newaddr, 0); 201 fdb_insert(br, NULL, newaddr, 0);
155 202
@@ -159,14 +206,16 @@ void br_fdb_change_mac_address(struct net_bridge *br, const u8 *newaddr)
159 */ 206 */
160 pv = br_get_vlan_info(br); 207 pv = br_get_vlan_info(br);
161 if (!pv) 208 if (!pv)
162 return; 209 goto out;
163 210
164 for_each_set_bit_from(vid, pv->vlan_bitmap, VLAN_N_VID) { 211 for_each_set_bit_from(vid, pv->vlan_bitmap, VLAN_N_VID) {
165 f = __br_fdb_get(br, br->dev->dev_addr, vid); 212 f = __br_fdb_get(br, br->dev->dev_addr, vid);
166 if (f && f->is_local && !f->dst) 213 if (f && f->is_local && !f->dst)
167 fdb_delete(br, f); 214 fdb_delete_local(br, NULL, f);
168 fdb_insert(br, NULL, newaddr, vid); 215 fdb_insert(br, NULL, newaddr, vid);
169 } 216 }
217out:
218 spin_unlock_bh(&br->hash_lock);
170} 219}
171 220
172void br_fdb_cleanup(unsigned long _data) 221void br_fdb_cleanup(unsigned long _data)
@@ -235,25 +284,11 @@ void br_fdb_delete_by_port(struct net_bridge *br,
235 284
236 if (f->is_static && !do_all) 285 if (f->is_static && !do_all)
237 continue; 286 continue;
238 /*
239 * if multiple ports all have the same device address
240 * then when one port is deleted, assign
241 * the local entry to other port
242 */
243 if (f->is_local) {
244 struct net_bridge_port *op;
245 list_for_each_entry(op, &br->port_list, list) {
246 if (op != p &&
247 ether_addr_equal(op->dev->dev_addr,
248 f->addr.addr)) {
249 f->dst = op;
250 goto skip_delete;
251 }
252 }
253 }
254 287
255 fdb_delete(br, f); 288 if (f->is_local)
256 skip_delete: ; 289 fdb_delete_local(br, p, f);
290 else
291 fdb_delete(br, f);
257 } 292 }
258 } 293 }
259 spin_unlock_bh(&br->hash_lock); 294 spin_unlock_bh(&br->hash_lock);
@@ -397,6 +432,7 @@ static struct net_bridge_fdb_entry *fdb_create(struct hlist_head *head,
397 fdb->vlan_id = vid; 432 fdb->vlan_id = vid;
398 fdb->is_local = 0; 433 fdb->is_local = 0;
399 fdb->is_static = 0; 434 fdb->is_static = 0;
435 fdb->added_by_user = 0;
400 fdb->updated = fdb->used = jiffies; 436 fdb->updated = fdb->used = jiffies;
401 hlist_add_head_rcu(&fdb->hlist, head); 437 hlist_add_head_rcu(&fdb->hlist, head);
402 } 438 }
@@ -447,7 +483,7 @@ int br_fdb_insert(struct net_bridge *br, struct net_bridge_port *source,
447} 483}
448 484
449void br_fdb_update(struct net_bridge *br, struct net_bridge_port *source, 485void br_fdb_update(struct net_bridge *br, struct net_bridge_port *source,
450 const unsigned char *addr, u16 vid) 486 const unsigned char *addr, u16 vid, bool added_by_user)
451{ 487{
452 struct hlist_head *head = &br->hash[br_mac_hash(addr, vid)]; 488 struct hlist_head *head = &br->hash[br_mac_hash(addr, vid)];
453 struct net_bridge_fdb_entry *fdb; 489 struct net_bridge_fdb_entry *fdb;
@@ -473,13 +509,18 @@ void br_fdb_update(struct net_bridge *br, struct net_bridge_port *source,
473 /* fastpath: update of existing entry */ 509 /* fastpath: update of existing entry */
474 fdb->dst = source; 510 fdb->dst = source;
475 fdb->updated = jiffies; 511 fdb->updated = jiffies;
512 if (unlikely(added_by_user))
513 fdb->added_by_user = 1;
476 } 514 }
477 } else { 515 } else {
478 spin_lock(&br->hash_lock); 516 spin_lock(&br->hash_lock);
479 if (likely(!fdb_find(head, addr, vid))) { 517 if (likely(!fdb_find(head, addr, vid))) {
480 fdb = fdb_create(head, source, addr, vid); 518 fdb = fdb_create(head, source, addr, vid);
481 if (fdb) 519 if (fdb) {
520 if (unlikely(added_by_user))
521 fdb->added_by_user = 1;
482 fdb_notify(br, fdb, RTM_NEWNEIGH); 522 fdb_notify(br, fdb, RTM_NEWNEIGH);
523 }
483 } 524 }
484 /* else we lose race and someone else inserts 525 /* else we lose race and someone else inserts
485 * it first, don't bother updating 526 * it first, don't bother updating
@@ -647,6 +688,7 @@ static int fdb_add_entry(struct net_bridge_port *source, const __u8 *addr,
647 688
648 modified = true; 689 modified = true;
649 } 690 }
691 fdb->added_by_user = 1;
650 692
651 fdb->used = jiffies; 693 fdb->used = jiffies;
652 if (modified) { 694 if (modified) {
@@ -664,7 +706,7 @@ static int __br_fdb_add(struct ndmsg *ndm, struct net_bridge_port *p,
664 706
665 if (ndm->ndm_flags & NTF_USE) { 707 if (ndm->ndm_flags & NTF_USE) {
666 rcu_read_lock(); 708 rcu_read_lock();
667 br_fdb_update(p->br, p, addr, vid); 709 br_fdb_update(p->br, p, addr, vid, true);
668 rcu_read_unlock(); 710 rcu_read_unlock();
669 } else { 711 } else {
670 spin_lock_bh(&p->br->hash_lock); 712 spin_lock_bh(&p->br->hash_lock);
@@ -749,8 +791,7 @@ out:
749 return err; 791 return err;
750} 792}
751 793
752int fdb_delete_by_addr(struct net_bridge *br, const u8 *addr, 794static int fdb_delete_by_addr(struct net_bridge *br, const u8 *addr, u16 vlan)
753 u16 vlan)
754{ 795{
755 struct hlist_head *head = &br->hash[br_mac_hash(addr, vlan)]; 796 struct hlist_head *head = &br->hash[br_mac_hash(addr, vlan)];
756 struct net_bridge_fdb_entry *fdb; 797 struct net_bridge_fdb_entry *fdb;