diff options
Diffstat (limited to 'net/bridge/br_fdb.c')
-rw-r--r-- | net/bridge/br_fdb.c | 16 |
1 files changed, 12 insertions, 4 deletions
diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c index c5f5a4a933f4..ce5411995a63 100644 --- a/net/bridge/br_fdb.c +++ b/net/bridge/br_fdb.c | |||
@@ -104,7 +104,7 @@ void br_fdb_changeaddr(struct net_bridge_port *p, const unsigned char *newaddr) | |||
104 | struct net_bridge_fdb_entry *f; | 104 | struct net_bridge_fdb_entry *f; |
105 | 105 | ||
106 | f = hlist_entry(h, struct net_bridge_fdb_entry, hlist); | 106 | f = hlist_entry(h, struct net_bridge_fdb_entry, hlist); |
107 | if (f->dst == p && f->is_local) { | 107 | if (f->dst == p && f->is_local && !f->added_by_user) { |
108 | /* maybe another port has same hw addr? */ | 108 | /* maybe another port has same hw addr? */ |
109 | struct net_bridge_port *op; | 109 | struct net_bridge_port *op; |
110 | u16 vid = f->vlan_id; | 110 | u16 vid = f->vlan_id; |
@@ -247,6 +247,7 @@ void br_fdb_delete_by_port(struct net_bridge *br, | |||
247 | ether_addr_equal(op->dev->dev_addr, | 247 | ether_addr_equal(op->dev->dev_addr, |
248 | f->addr.addr)) { | 248 | f->addr.addr)) { |
249 | f->dst = op; | 249 | f->dst = op; |
250 | f->added_by_user = 0; | ||
250 | goto skip_delete; | 251 | goto skip_delete; |
251 | } | 252 | } |
252 | } | 253 | } |
@@ -397,6 +398,7 @@ static struct net_bridge_fdb_entry *fdb_create(struct hlist_head *head, | |||
397 | fdb->vlan_id = vid; | 398 | fdb->vlan_id = vid; |
398 | fdb->is_local = 0; | 399 | fdb->is_local = 0; |
399 | fdb->is_static = 0; | 400 | fdb->is_static = 0; |
401 | fdb->added_by_user = 0; | ||
400 | fdb->updated = fdb->used = jiffies; | 402 | fdb->updated = fdb->used = jiffies; |
401 | hlist_add_head_rcu(&fdb->hlist, head); | 403 | hlist_add_head_rcu(&fdb->hlist, head); |
402 | } | 404 | } |
@@ -447,7 +449,7 @@ int br_fdb_insert(struct net_bridge *br, struct net_bridge_port *source, | |||
447 | } | 449 | } |
448 | 450 | ||
449 | void br_fdb_update(struct net_bridge *br, struct net_bridge_port *source, | 451 | void br_fdb_update(struct net_bridge *br, struct net_bridge_port *source, |
450 | const unsigned char *addr, u16 vid) | 452 | const unsigned char *addr, u16 vid, bool added_by_user) |
451 | { | 453 | { |
452 | struct hlist_head *head = &br->hash[br_mac_hash(addr, vid)]; | 454 | struct hlist_head *head = &br->hash[br_mac_hash(addr, vid)]; |
453 | struct net_bridge_fdb_entry *fdb; | 455 | struct net_bridge_fdb_entry *fdb; |
@@ -473,13 +475,18 @@ void br_fdb_update(struct net_bridge *br, struct net_bridge_port *source, | |||
473 | /* fastpath: update of existing entry */ | 475 | /* fastpath: update of existing entry */ |
474 | fdb->dst = source; | 476 | fdb->dst = source; |
475 | fdb->updated = jiffies; | 477 | fdb->updated = jiffies; |
478 | if (unlikely(added_by_user)) | ||
479 | fdb->added_by_user = 1; | ||
476 | } | 480 | } |
477 | } else { | 481 | } else { |
478 | spin_lock(&br->hash_lock); | 482 | spin_lock(&br->hash_lock); |
479 | if (likely(!fdb_find(head, addr, vid))) { | 483 | if (likely(!fdb_find(head, addr, vid))) { |
480 | fdb = fdb_create(head, source, addr, vid); | 484 | fdb = fdb_create(head, source, addr, vid); |
481 | if (fdb) | 485 | if (fdb) { |
486 | if (unlikely(added_by_user)) | ||
487 | fdb->added_by_user = 1; | ||
482 | fdb_notify(br, fdb, RTM_NEWNEIGH); | 488 | fdb_notify(br, fdb, RTM_NEWNEIGH); |
489 | } | ||
483 | } | 490 | } |
484 | /* else we lose race and someone else inserts | 491 | /* else we lose race and someone else inserts |
485 | * it first, don't bother updating | 492 | * it first, don't bother updating |
@@ -647,6 +654,7 @@ static int fdb_add_entry(struct net_bridge_port *source, const __u8 *addr, | |||
647 | 654 | ||
648 | modified = true; | 655 | modified = true; |
649 | } | 656 | } |
657 | fdb->added_by_user = 1; | ||
650 | 658 | ||
651 | fdb->used = jiffies; | 659 | fdb->used = jiffies; |
652 | if (modified) { | 660 | if (modified) { |
@@ -664,7 +672,7 @@ static int __br_fdb_add(struct ndmsg *ndm, struct net_bridge_port *p, | |||
664 | 672 | ||
665 | if (ndm->ndm_flags & NTF_USE) { | 673 | if (ndm->ndm_flags & NTF_USE) { |
666 | rcu_read_lock(); | 674 | rcu_read_lock(); |
667 | br_fdb_update(p->br, p, addr, vid); | 675 | br_fdb_update(p->br, p, addr, vid, true); |
668 | rcu_read_unlock(); | 676 | rcu_read_unlock(); |
669 | } else { | 677 | } else { |
670 | spin_lock_bh(&p->br->hash_lock); | 678 | spin_lock_bh(&p->br->hash_lock); |