summaryrefslogtreecommitdiff
path: root/net/bridge/br_mdb.c
diff options
context:
space:
mode:
authorSatish Ashok <sashok@cumulusnetworks.com>2015-08-03 14:29:16 +0300
committerDavid S. Miller <davem@davemloft.net>2015-08-04 01:43:35 +0300
commite44deb2f0cce9183ca94d14effd4170a35eec31d (patch)
treea95e73acd81b76f1104edc37d0c3a82b08fceab5 /net/bridge/br_mdb.c
parent0edc535e96621e41e2d3e7c240e68524d1968807 (diff)
downloadlinux-e44deb2f0cce9183ca94d14effd4170a35eec31d.tar.xz
bridge: mdb: add/del entry on all vlans if vlan_filter is enabled and vid is 0
Before this patch when a vid was not specified, the entry was added with vid 0 which is useless when vlan_filtering is enabled. This patch makes the entry to be added on all configured vlans when vlan filtering is enabled and respectively deleted from all, if the entry vid is 0. This is also closer to the way fdb works with regard to vid 0 and vlan filtering. Example: Setup: $ bridge vlan add vid 256 dev eth4 $ bridge vlan add vid 1024 dev eth4 $ bridge vlan add vid 64 dev eth3 $ bridge vlan add vid 128 dev eth3 $ bridge vlan port vlan ids eth3 1 PVID Egress Untagged 64 128 eth4 1 PVID Egress Untagged 256 1024 $ echo 1 > /sys/class/net/br0/bridge/vlan_filtering Before: $ bridge mdb add dev br0 port eth3 grp 239.0.0.1 $ bridge mdb dev br0 port eth3 grp 239.0.0.1 temp After: $ bridge mdb add dev br0 port eth3 grp 239.0.0.1 $ bridge mdb dev br0 port eth3 grp 239.0.0.1 temp vid 1 dev br0 port eth3 grp 239.0.0.1 temp vid 128 dev br0 port eth3 grp 239.0.0.1 temp vid 64 Signed-off-by: Satish Ashok <sashok@cumulusnetworks.com> Signed-off-by: Nikolay Aleksandrov <nikolay@cumulusnetworks.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/bridge/br_mdb.c')
-rw-r--r--net/bridge/br_mdb.c68
1 files changed, 60 insertions, 8 deletions
diff --git a/net/bridge/br_mdb.c b/net/bridge/br_mdb.c
index 6a592856da1c..1df3ef4a73b9 100644
--- a/net/bridge/br_mdb.c
+++ b/net/bridge/br_mdb.c
@@ -464,8 +464,11 @@ static int __br_mdb_add(struct net *net, struct net_bridge *br,
static int br_mdb_add(struct sk_buff *skb, struct nlmsghdr *nlh)
{
struct net *net = sock_net(skb->sk);
+ unsigned short vid = VLAN_N_VID;
+ struct net_device *dev, *pdev;
struct br_mdb_entry *entry;
- struct net_device *dev;
+ struct net_bridge_port *p;
+ struct net_port_vlans *pv;
struct net_bridge *br;
int err;
@@ -475,9 +478,32 @@ static int br_mdb_add(struct sk_buff *skb, struct nlmsghdr *nlh)
br = netdev_priv(dev);
- err = __br_mdb_add(net, br, entry);
- if (!err)
- __br_mdb_notify(dev, entry, RTM_NEWMDB);
+ /* If vlan filtering is enabled and VLAN is not specified
+ * install mdb entry on all vlans configured on the port.
+ */
+ pdev = __dev_get_by_index(net, entry->ifindex);
+ if (!pdev)
+ return -ENODEV;
+
+ p = br_port_get_rtnl(pdev);
+ if (!p || p->br != br || p->state == BR_STATE_DISABLED)
+ return -EINVAL;
+
+ pv = nbp_get_vlan_info(p);
+ if (br->vlan_enabled && pv && entry->vid == 0) {
+ for_each_set_bit(vid, pv->vlan_bitmap, VLAN_N_VID) {
+ entry->vid = vid;
+ err = __br_mdb_add(net, br, entry);
+ if (err)
+ break;
+ __br_mdb_notify(dev, entry, RTM_NEWMDB);
+ }
+ } else {
+ err = __br_mdb_add(net, br, entry);
+ if (!err)
+ __br_mdb_notify(dev, entry, RTM_NEWMDB);
+ }
+
return err;
}
@@ -539,8 +565,12 @@ unlock:
static int br_mdb_del(struct sk_buff *skb, struct nlmsghdr *nlh)
{
- struct net_device *dev;
+ struct net *net = sock_net(skb->sk);
+ unsigned short vid = VLAN_N_VID;
+ struct net_device *dev, *pdev;
struct br_mdb_entry *entry;
+ struct net_bridge_port *p;
+ struct net_port_vlans *pv;
struct net_bridge *br;
int err;
@@ -550,9 +580,31 @@ static int br_mdb_del(struct sk_buff *skb, struct nlmsghdr *nlh)
br = netdev_priv(dev);
- err = __br_mdb_del(br, entry);
- if (!err)
- __br_mdb_notify(dev, entry, RTM_DELMDB);
+ /* If vlan filtering is enabled and VLAN is not specified
+ * delete mdb entry on all vlans configured on the port.
+ */
+ pdev = __dev_get_by_index(net, entry->ifindex);
+ if (!pdev)
+ return -ENODEV;
+
+ p = br_port_get_rtnl(pdev);
+ if (!p || p->br != br || p->state == BR_STATE_DISABLED)
+ return -EINVAL;
+
+ pv = nbp_get_vlan_info(p);
+ if (br->vlan_enabled && pv && entry->vid == 0) {
+ for_each_set_bit(vid, pv->vlan_bitmap, VLAN_N_VID) {
+ entry->vid = vid;
+ err = __br_mdb_del(br, entry);
+ if (!err)
+ __br_mdb_notify(dev, entry, RTM_DELMDB);
+ }
+ } else {
+ err = __br_mdb_del(br, entry);
+ if (!err)
+ __br_mdb_notify(dev, entry, RTM_DELMDB);
+ }
+
return err;
}