Commit 43598813386f6205edf3c21f1fe97f731ccb4f15

Authored by stephen hemminger
Committed by David S. Miller
1 parent 31e8a49c16

bridge: add local MAC address to forwarding table (v2)

If user has configured a MAC address that is not one of the existing
ports of the bridge, then we need to add a special entry in the forwarding
table. This forwarding table entry has no outgoing port so it has to be
treated a little differently. The special entry is reported by the netlink
interface with ifindex of bridge, but ignored by the old interface since there
is no usable way to put it in the ABI.

Reported-by: Koki Sanagi <sanagi.koki@jp.fujitsu.com>
Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

Showing 4 changed files with 25 additions and 5 deletions Side-by-side Diff

net/bridge/br_device.c
... ... @@ -170,8 +170,11 @@
170 170 return -EINVAL;
171 171  
172 172 spin_lock_bh(&br->lock);
173   - memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN);
174   - br_stp_change_bridge_id(br, addr->sa_data);
  173 + if (compare_ether_addr(dev->dev_addr, addr->sa_data)) {
  174 + memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN);
  175 + br_fdb_change_mac_address(br, addr->sa_data);
  176 + br_stp_change_bridge_id(br, addr->sa_data);
  177 + }
175 178 br->flags |= BR_SET_MAC_ADDR;
176 179 spin_unlock_bh(&br->lock);
177 180  
... ... @@ -127,6 +127,18 @@
127 127 spin_unlock_bh(&br->hash_lock);
128 128 }
129 129  
  130 +void br_fdb_change_mac_address(struct net_bridge *br, const u8 *newaddr)
  131 +{
  132 + struct net_bridge_fdb_entry *f;
  133 +
  134 + /* If old entry was unassociated with any port, then delete it. */
  135 + f = __br_fdb_get(br, br->dev->dev_addr);
  136 + if (f && f->is_local && !f->dst)
  137 + fdb_delete(br, f);
  138 +
  139 + fdb_insert(br, NULL, newaddr);
  140 +}
  141 +
130 142 void br_fdb_cleanup(unsigned long _data)
131 143 {
132 144 struct net_bridge *br = (struct net_bridge *)_data;
... ... @@ -250,7 +262,7 @@
250 262 ret = 0;
251 263 else {
252 264 fdb = __br_fdb_get(port->br, addr);
253   - ret = fdb && fdb->dst->dev != dev &&
  265 + ret = fdb && fdb->dst && fdb->dst->dev != dev &&
254 266 fdb->dst->state == BR_STATE_FORWARDING;
255 267 }
256 268 rcu_read_unlock();
... ... @@ -282,6 +294,10 @@
282 294 if (has_expired(br, f))
283 295 continue;
284 296  
  297 + /* ignore pseudo entry for local MAC address */
  298 + if (!f->dst)
  299 + continue;
  300 +
285 301 if (skip) {
286 302 --skip;
287 303 continue;
... ... @@ -468,7 +484,7 @@
468 484 ndm->ndm_pad2 = 0;
469 485 ndm->ndm_flags = 0;
470 486 ndm->ndm_type = 0;
471   - ndm->ndm_ifindex = fdb->dst->dev->ifindex;
  487 + ndm->ndm_ifindex = fdb->dst ? fdb->dst->dev->ifindex : br->dev->ifindex;
472 488 ndm->ndm_state = fdb_to_nud(fdb);
473 489  
474 490 NLA_PUT(skb, NDA_LLADDR, ETH_ALEN, &fdb->addr);
net/bridge/br_forward.c
... ... @@ -98,7 +98,7 @@
98 98 /* called with rcu_read_lock */
99 99 void br_deliver(const struct net_bridge_port *to, struct sk_buff *skb)
100 100 {
101   - if (should_deliver(to, skb)) {
  101 + if (to && should_deliver(to, skb)) {
102 102 __br_deliver(to, skb);
103 103 return;
104 104 }
net/bridge/br_private.h
... ... @@ -348,6 +348,7 @@
348 348 extern void br_fdb_flush(struct net_bridge *br);
349 349 extern void br_fdb_changeaddr(struct net_bridge_port *p,
350 350 const unsigned char *newaddr);
  351 +extern void br_fdb_change_mac_address(struct net_bridge *br, const u8 *newaddr);
351 352 extern void br_fdb_cleanup(unsigned long arg);
352 353 extern void br_fdb_delete_by_port(struct net_bridge *br,
353 354 const struct net_bridge_port *p, int do_all);