Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 352449
b: refs/heads/master
c: bc9a25d
h: refs/heads/master
i:
  352447: 89efcc5
v: v3
  • Loading branch information
Vlad Yasevich authored and David S. Miller committed Feb 14, 2013
1 parent b5ee8f6 commit fc4fcfd
Show file tree
Hide file tree
Showing 5 changed files with 126 additions and 26 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 1690be63a27b20ae65c792729a44f5970561ffa4
refs/heads/master: bc9a25d21ef8bad30e259af5114ccfb845c066db
61 changes: 46 additions & 15 deletions trunk/net/bridge/br_fdb.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@

static struct kmem_cache *br_fdb_cache __read_mostly;
static int fdb_insert(struct net_bridge *br, struct net_bridge_port *source,
const unsigned char *addr);
const unsigned char *addr, u16 vid);
static void fdb_notify(struct net_bridge *br,
const struct net_bridge_fdb_entry *, int);

Expand Down Expand Up @@ -92,6 +92,7 @@ static void fdb_delete(struct net_bridge *br, struct net_bridge_fdb_entry *f)
void br_fdb_changeaddr(struct net_bridge_port *p, const unsigned char *newaddr)
{
struct net_bridge *br = p->br;
bool no_vlan = (nbp_get_vlan_info(p) == NULL) ? true : false;
int i;

spin_lock_bh(&br->hash_lock);
Expand All @@ -106,38 +107,68 @@ void br_fdb_changeaddr(struct net_bridge_port *p, const unsigned char *newaddr)
if (f->dst == p && f->is_local) {
/* maybe another port has same hw addr? */
struct net_bridge_port *op;
u16 vid = f->vlan_id;
list_for_each_entry(op, &br->port_list, list) {
if (op != p &&
ether_addr_equal(op->dev->dev_addr,
f->addr.addr)) {
f->addr.addr) &&
nbp_vlan_find(op, vid)) {
f->dst = op;
goto insert;
}
}

/* delete old one */
fdb_delete(br, f);
goto insert;
insert:
/* insert new address, may fail if invalid
* address or dup.
*/
fdb_insert(br, p, newaddr, vid);

/* if this port has no vlan information
* configured, we can safely be done at
* this point.
*/
if (no_vlan)
goto done;
}
}
}
insert:
/* insert new address, may fail if invalid address or dup. */
fdb_insert(br, p, newaddr);

done:
spin_unlock_bh(&br->hash_lock);
}

void br_fdb_change_mac_address(struct net_bridge *br, const u8 *newaddr)
{
struct net_bridge_fdb_entry *f;
struct net_port_vlans *pv;
u16 vid = 0;

/* If old entry was unassociated with any port, then delete it. */
f = __br_fdb_get(br, br->dev->dev_addr, 0);
if (f && f->is_local && !f->dst)
fdb_delete(br, f);

fdb_insert(br, NULL, newaddr);
fdb_insert(br, NULL, newaddr, 0);

/* Now remove and add entries for every VLAN configured on the
* bridge. This function runs under RTNL so the bitmap will not
* change from under us.
*/
pv = br_get_vlan_info(br);
if (!pv)
return;

for (vid = find_next_bit(pv->vlan_bitmap, BR_VLAN_BITMAP_LEN, vid);
vid < BR_VLAN_BITMAP_LEN;
vid = find_next_bit(pv->vlan_bitmap, BR_VLAN_BITMAP_LEN, vid+1)) {
f = __br_fdb_get(br, br->dev->dev_addr, vid);
if (f && f->is_local && !f->dst)
fdb_delete(br, f);
fdb_insert(br, NULL, newaddr, vid);
}
}

void br_fdb_cleanup(unsigned long _data)
Expand Down Expand Up @@ -379,15 +410,15 @@ static struct net_bridge_fdb_entry *fdb_create(struct hlist_head *head,
}

static int fdb_insert(struct net_bridge *br, struct net_bridge_port *source,
const unsigned char *addr)
const unsigned char *addr, u16 vid)
{
struct hlist_head *head = &br->hash[br_mac_hash(addr, 0)];
struct hlist_head *head = &br->hash[br_mac_hash(addr, vid)];
struct net_bridge_fdb_entry *fdb;

if (!is_valid_ether_addr(addr))
return -EINVAL;

fdb = fdb_find(head, addr, 0);
fdb = fdb_find(head, addr, vid);
if (fdb) {
/* it is okay to have multiple ports with same
* address, just use the first one.
Expand All @@ -400,7 +431,7 @@ static int fdb_insert(struct net_bridge *br, struct net_bridge_port *source,
fdb_delete(br, fdb);
}

fdb = fdb_create(head, source, addr, 0);
fdb = fdb_create(head, source, addr, vid);
if (!fdb)
return -ENOMEM;

Expand All @@ -411,12 +442,12 @@ static int fdb_insert(struct net_bridge *br, struct net_bridge_port *source,

/* Add entry for local address of interface */
int br_fdb_insert(struct net_bridge *br, struct net_bridge_port *source,
const unsigned char *addr)
const unsigned char *addr, u16 vid)
{
int ret;

spin_lock_bh(&br->hash_lock);
ret = fdb_insert(br, source, addr);
ret = fdb_insert(br, source, addr, vid);
spin_unlock_bh(&br->hash_lock);
return ret;
}
Expand Down Expand Up @@ -712,8 +743,8 @@ int br_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
return err;
}

static int fdb_delete_by_addr(struct net_bridge *br, const u8 *addr,
u16 vlan)
int fdb_delete_by_addr(struct net_bridge *br, const u8 *addr,
u16 vlan)
{
struct hlist_head *head = &br->hash[br_mac_hash(addr, vlan)];
struct net_bridge_fdb_entry *fdb;
Expand Down
2 changes: 1 addition & 1 deletion trunk/net/bridge/br_if.c
Original file line number Diff line number Diff line change
Expand Up @@ -397,7 +397,7 @@ int br_add_if(struct net_bridge *br, struct net_device *dev)

dev_set_mtu(br->dev, br_min_mtu(br));

if (br_fdb_insert(br, p, dev->dev_addr))
if (br_fdb_insert(br, p, dev->dev_addr, 0))
netdev_err(dev, "failed insert local address bridge forwarding table\n");

kobject_uevent(&p->kobj, KOBJ_ADD);
Expand Down
10 changes: 9 additions & 1 deletion trunk/net/bridge/br_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -382,11 +382,13 @@ extern int br_fdb_fillbuf(struct net_bridge *br, void *buf,
unsigned long count, unsigned long off);
extern int br_fdb_insert(struct net_bridge *br,
struct net_bridge_port *source,
const unsigned char *addr);
const unsigned char *addr,
u16 vid);
extern void br_fdb_update(struct net_bridge *br,
struct net_bridge_port *source,
const unsigned char *addr,
u16 vid);
extern int fdb_delete_by_addr(struct net_bridge *br, const u8 *addr, u16 vid);

extern int br_fdb_delete(struct ndmsg *ndm, struct nlattr *tb[],
struct net_device *dev,
Expand Down Expand Up @@ -573,6 +575,7 @@ extern int br_vlan_filter_toggle(struct net_bridge *br, unsigned long val);
extern int nbp_vlan_add(struct net_bridge_port *port, u16 vid, u16 flags);
extern int nbp_vlan_delete(struct net_bridge_port *port, u16 vid);
extern void nbp_vlan_flush(struct net_bridge_port *port);
extern bool nbp_vlan_find(struct net_bridge_port *port, u16 vid);

static inline struct net_port_vlans *br_get_vlan_info(
const struct net_bridge *br)
Expand Down Expand Up @@ -676,6 +679,11 @@ static inline struct net_port_vlans *nbp_get_vlan_info(
return NULL;
}

static inline bool nbp_vlan_find(struct net_bridge_port *port, u16 vid)
{
return false;
}

static inline u16 br_vlan_get_tag(const struct sk_buff *skb, u16 *tag)
{
return 0;
Expand Down
77 changes: 69 additions & 8 deletions trunk/net/bridge/br_vlan.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ static void __vlan_delete_pvid(struct net_port_vlans *v, u16 vid)

static int __vlan_add(struct net_port_vlans *v, u16 vid, u16 flags)
{
struct net_bridge_port *p = NULL;
struct net_bridge *br;
struct net_device *dev;
int err;

if (test_bit(vid, v->vlan_bitmap)) {
Expand All @@ -33,19 +36,35 @@ static int __vlan_add(struct net_port_vlans *v, u16 vid, u16 flags)
return 0;
}

if (v->port_idx && vid) {
struct net_device *dev = v->parent.port->dev;
if (vid) {
if (v->port_idx) {
p = v->parent.port;
br = p->br;
dev = p->dev;
} else {
br = v->parent.br;
dev = br->dev;
}

/* Add VLAN to the device filter if it is supported.
* Stricly speaking, this is not necessary now, since devices
* are made promiscuous by the bridge, but if that ever changes
* this code will allow tagged traffic to enter the bridge.
*/
if (dev->features & NETIF_F_HW_VLAN_FILTER) {
if (p && (dev->features & NETIF_F_HW_VLAN_FILTER)) {
/* Add VLAN to the device filter if it is supported.
* Stricly speaking, this is not necessary now, since
* devices are made promiscuous by the bridge, but if
* that ever changes this code will allow tagged
* traffic to enter the bridge.
*/
err = dev->netdev_ops->ndo_vlan_rx_add_vid(dev, vid);
if (err)
return err;
}

err = br_fdb_insert(br, p, dev->dev_addr, vid);
if (err) {
br_err(br, "failed insert local address into bridge "
"forwarding table\n");
goto out_filt;
}

}

set_bit(vid, v->vlan_bitmap);
Expand All @@ -54,6 +73,11 @@ static int __vlan_add(struct net_port_vlans *v, u16 vid, u16 flags)
__vlan_add_pvid(v, vid);

return 0;

out_filt:
if (p && (dev->features & NETIF_F_HW_VLAN_FILTER))
dev->netdev_ops->ndo_vlan_rx_kill_vid(dev, vid);
return err;
}

static int __vlan_del(struct net_port_vlans *v, u16 vid)
Expand Down Expand Up @@ -253,6 +277,15 @@ int br_vlan_delete(struct net_bridge *br, u16 vid)
if (!pv)
return -EINVAL;

if (vid) {
/* If the VID !=0 remove fdb for this vid. VID 0 is special
* in that it's the default and is always there in the fdb.
*/
spin_lock_bh(&br->hash_lock);
fdb_delete_by_addr(br, br->dev->dev_addr, vid);
spin_unlock_bh(&br->hash_lock);
}

__vlan_del(pv, vid);
return 0;
}
Expand Down Expand Up @@ -329,6 +362,15 @@ int nbp_vlan_delete(struct net_bridge_port *port, u16 vid)
if (!pv)
return -EINVAL;

if (vid) {
/* If the VID !=0 remove fdb for this vid. VID 0 is special
* in that it's the default and is always there in the fdb.
*/
spin_lock_bh(&port->br->hash_lock);
fdb_delete_by_addr(port->br, port->dev->dev_addr, vid);
spin_unlock_bh(&port->br->hash_lock);
}

return __vlan_del(pv, vid);
}

Expand All @@ -344,3 +386,22 @@ void nbp_vlan_flush(struct net_bridge_port *port)

__vlan_flush(pv);
}

bool nbp_vlan_find(struct net_bridge_port *port, u16 vid)
{
struct net_port_vlans *pv;
bool found = false;

rcu_read_lock();
pv = rcu_dereference(port->vlan_info);

if (!pv)
goto out;

if (test_bit(vid, pv->vlan_bitmap))
found = true;

out:
rcu_read_unlock();
return found;
}

0 comments on commit fc4fcfd

Please sign in to comment.