aboutsummaryrefslogtreecommitdiffstats
path: root/net/bridge/br_fdb.c
diff options
context:
space:
mode:
authorVlad Yasevich <vyasevic@redhat.com>2014-05-16 09:59:19 -0400
committerDavid S. Miller <davem@davemloft.net>2014-05-16 17:06:33 -0400
commit145beee8d6bbd18dbebf9f71a40ba99af80d71f7 (patch)
tree1da0a5d6c374686bba0836b7f2e9c521a5f60ad8 /net/bridge/br_fdb.c
parentf3a6ddf15209cfad90b83e04168f42a5d9c8cc17 (diff)
bridge: Add addresses from static fdbs to non-promisc ports
When a static fdb entry is created, add the mac address from this fdb entry to any ports that are currently running in non-promiscuous mode. These ports need this data so that they can receive traffic destined to these addresses. By default ports start in promiscuous mode, so this feature is disabled. Acked-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Vlad Yasevich <vyasevic@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/bridge/br_fdb.c')
-rw-r--r--net/bridge/br_fdb.c75
1 files changed, 69 insertions, 6 deletions
diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c
index fe124e59a344..648d0e849595 100644
--- a/net/bridge/br_fdb.c
+++ b/net/bridge/br_fdb.c
@@ -85,8 +85,58 @@ static void fdb_rcu_free(struct rcu_head *head)
85 kmem_cache_free(br_fdb_cache, ent); 85 kmem_cache_free(br_fdb_cache, ent);
86} 86}
87 87
88/* When a static FDB entry is added, the mac address from the entry is
89 * added to the bridge private HW address list and all required ports
90 * are then updated with the new information.
91 * Called under RTNL.
92 */
93static void fdb_add_hw(struct net_bridge *br, const unsigned char *addr)
94{
95 int err;
96 struct net_bridge_port *p, *tmp;
97
98 ASSERT_RTNL();
99
100 list_for_each_entry(p, &br->port_list, list) {
101 if (!br_promisc_port(p)) {
102 err = dev_uc_add(p->dev, addr);
103 if (err)
104 goto undo;
105 }
106 }
107
108 return;
109undo:
110 list_for_each_entry(tmp, &br->port_list, list) {
111 if (tmp == p)
112 break;
113 if (!br_promisc_port(tmp))
114 dev_uc_del(tmp->dev, addr);
115 }
116}
117
118/* When a static FDB entry is deleted, the HW address from that entry is
119 * also removed from the bridge private HW address list and updates all
120 * the ports with needed information.
121 * Called under RTNL.
122 */
123static void fdb_del_hw(struct net_bridge *br, const unsigned char *addr)
124{
125 struct net_bridge_port *p;
126
127 ASSERT_RTNL();
128
129 list_for_each_entry(p, &br->port_list, list) {
130 if (!br_promisc_port(p))
131 dev_uc_del(p->dev, addr);
132 }
133}
134
88static void fdb_delete(struct net_bridge *br, struct net_bridge_fdb_entry *f) 135static void fdb_delete(struct net_bridge *br, struct net_bridge_fdb_entry *f)
89{ 136{
137 if (f->is_static)
138 fdb_del_hw(br, f->addr.addr);
139
90 hlist_del_rcu(&f->hlist); 140 hlist_del_rcu(&f->hlist);
91 fdb_notify(br, f, RTM_DELNEIGH); 141 fdb_notify(br, f, RTM_DELNEIGH);
92 call_rcu(&f->rcu, fdb_rcu_free); 142 call_rcu(&f->rcu, fdb_rcu_free);
@@ -466,6 +516,7 @@ static int fdb_insert(struct net_bridge *br, struct net_bridge_port *source,
466 return -ENOMEM; 516 return -ENOMEM;
467 517
468 fdb->is_local = fdb->is_static = 1; 518 fdb->is_local = fdb->is_static = 1;
519 fdb_add_hw(br, addr);
469 fdb_notify(br, fdb, RTM_NEWNEIGH); 520 fdb_notify(br, fdb, RTM_NEWNEIGH);
470 return 0; 521 return 0;
471} 522}
@@ -678,13 +729,25 @@ static int fdb_add_entry(struct net_bridge_port *source, const __u8 *addr,
678 } 729 }
679 730
680 if (fdb_to_nud(fdb) != state) { 731 if (fdb_to_nud(fdb) != state) {
681 if (state & NUD_PERMANENT) 732 if (state & NUD_PERMANENT) {
682 fdb->is_local = fdb->is_static = 1; 733 fdb->is_local = 1;
683 else if (state & NUD_NOARP) { 734 if (!fdb->is_static) {
735 fdb->is_static = 1;
736 fdb_add_hw(br, addr);
737 }
738 } else if (state & NUD_NOARP) {
684 fdb->is_local = 0; 739 fdb->is_local = 0;
685 fdb->is_static = 1; 740 if (!fdb->is_static) {
686 } else 741 fdb->is_static = 1;
687 fdb->is_local = fdb->is_static = 0; 742 fdb_add_hw(br, addr);
743 }
744 } else {
745 fdb->is_local = 0;
746 if (fdb->is_static) {
747 fdb->is_static = 0;
748 fdb_del_hw(br, addr);
749 }
750 }
688 751
689 modified = true; 752 modified = true;
690 } 753 }