mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-15 08:44:14 +08:00
net: bridge: mdb: allow add/delete for host-joined groups
Currently this is needed only for user-space compatibility, so similar object adds/deletes as the dumped ones would succeed. Later it can be used for L2 mcast MAC add/delete. v3: fix compiler warning (DaveM) v2: don't send a notification when used from user-space, arm the group timer if no ports are left after host entry del Signed-off-by: Nikolay Aleksandrov <nikolay@cumulusnetworks.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
e77b0c84e3
commit
1bc844ee0f
@ -616,6 +616,19 @@ static int br_mdb_add_group(struct net_bridge *br, struct net_bridge_port *port,
|
||||
return err;
|
||||
}
|
||||
|
||||
/* host join */
|
||||
if (!port) {
|
||||
/* don't allow any flags for host-joined groups */
|
||||
if (state)
|
||||
return -EINVAL;
|
||||
if (mp->host_joined)
|
||||
return -EEXIST;
|
||||
|
||||
br_multicast_host_join(mp, false);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (pp = &mp->ports;
|
||||
(p = mlock_dereference(*pp, br)) != NULL;
|
||||
pp = &p->next) {
|
||||
@ -640,19 +653,21 @@ static int __br_mdb_add(struct net *net, struct net_bridge *br,
|
||||
{
|
||||
struct br_ip ip;
|
||||
struct net_device *dev;
|
||||
struct net_bridge_port *p;
|
||||
struct net_bridge_port *p = NULL;
|
||||
int ret;
|
||||
|
||||
if (!netif_running(br->dev) || !br_opt_get(br, BROPT_MULTICAST_ENABLED))
|
||||
return -EINVAL;
|
||||
|
||||
dev = __dev_get_by_index(net, entry->ifindex);
|
||||
if (!dev)
|
||||
return -ENODEV;
|
||||
if (entry->ifindex != br->dev->ifindex) {
|
||||
dev = __dev_get_by_index(net, entry->ifindex);
|
||||
if (!dev)
|
||||
return -ENODEV;
|
||||
|
||||
p = br_port_get_rtnl(dev);
|
||||
if (!p || p->br != br || p->state == BR_STATE_DISABLED)
|
||||
return -EINVAL;
|
||||
p = br_port_get_rtnl(dev);
|
||||
if (!p || p->br != br || p->state == BR_STATE_DISABLED)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
__mdb_entry_to_br_ip(entry, &ip);
|
||||
|
||||
@ -667,9 +682,9 @@ static int br_mdb_add(struct sk_buff *skb, struct nlmsghdr *nlh,
|
||||
{
|
||||
struct net *net = sock_net(skb->sk);
|
||||
struct net_bridge_vlan_group *vg;
|
||||
struct net_bridge_port *p = NULL;
|
||||
struct net_device *dev, *pdev;
|
||||
struct br_mdb_entry *entry;
|
||||
struct net_bridge_port *p;
|
||||
struct net_bridge_vlan *v;
|
||||
struct net_bridge *br;
|
||||
int err;
|
||||
@ -680,15 +695,19 @@ static int br_mdb_add(struct sk_buff *skb, struct nlmsghdr *nlh,
|
||||
|
||||
br = netdev_priv(dev);
|
||||
|
||||
pdev = __dev_get_by_index(net, entry->ifindex);
|
||||
if (!pdev)
|
||||
return -ENODEV;
|
||||
if (entry->ifindex != br->dev->ifindex) {
|
||||
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;
|
||||
p = br_port_get_rtnl(pdev);
|
||||
if (!p || p->br != br || p->state == BR_STATE_DISABLED)
|
||||
return -EINVAL;
|
||||
vg = nbp_vlan_group(p);
|
||||
} else {
|
||||
vg = br_vlan_group(br);
|
||||
}
|
||||
|
||||
vg = nbp_vlan_group(p);
|
||||
/* If vlan filtering is enabled and VLAN is not specified
|
||||
* install mdb entry on all vlans configured on the port.
|
||||
*/
|
||||
@ -727,6 +746,15 @@ static int __br_mdb_del(struct net_bridge *br, struct br_mdb_entry *entry)
|
||||
if (!mp)
|
||||
goto unlock;
|
||||
|
||||
/* host leave */
|
||||
if (entry->ifindex == mp->br->dev->ifindex && mp->host_joined) {
|
||||
br_multicast_host_leave(mp, false);
|
||||
err = 0;
|
||||
if (!mp->ports && netif_running(br->dev))
|
||||
mod_timer(&mp->timer, jiffies);
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
for (pp = &mp->ports;
|
||||
(p = mlock_dereference(*pp, br)) != NULL;
|
||||
pp = &p->next) {
|
||||
@ -759,9 +787,9 @@ static int br_mdb_del(struct sk_buff *skb, struct nlmsghdr *nlh,
|
||||
{
|
||||
struct net *net = sock_net(skb->sk);
|
||||
struct net_bridge_vlan_group *vg;
|
||||
struct net_bridge_port *p = NULL;
|
||||
struct net_device *dev, *pdev;
|
||||
struct br_mdb_entry *entry;
|
||||
struct net_bridge_port *p;
|
||||
struct net_bridge_vlan *v;
|
||||
struct net_bridge *br;
|
||||
int err;
|
||||
@ -772,15 +800,19 @@ static int br_mdb_del(struct sk_buff *skb, struct nlmsghdr *nlh,
|
||||
|
||||
br = netdev_priv(dev);
|
||||
|
||||
pdev = __dev_get_by_index(net, entry->ifindex);
|
||||
if (!pdev)
|
||||
return -ENODEV;
|
||||
if (entry->ifindex != br->dev->ifindex) {
|
||||
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;
|
||||
p = br_port_get_rtnl(pdev);
|
||||
if (!p || p->br != br || p->state == BR_STATE_DISABLED)
|
||||
return -EINVAL;
|
||||
vg = nbp_vlan_group(p);
|
||||
} else {
|
||||
vg = br_vlan_group(br);
|
||||
}
|
||||
|
||||
vg = nbp_vlan_group(p);
|
||||
/* If vlan filtering is enabled and VLAN is not specified
|
||||
* delete mdb entry on all vlans configured on the port.
|
||||
*/
|
||||
|
@ -148,8 +148,7 @@ static void br_multicast_group_expired(struct timer_list *t)
|
||||
if (!netif_running(br->dev) || timer_pending(&mp->timer))
|
||||
goto out;
|
||||
|
||||
mp->host_joined = false;
|
||||
br_mdb_notify(br->dev, NULL, &mp->addr, RTM_DELMDB, 0);
|
||||
br_multicast_host_leave(mp, true);
|
||||
|
||||
if (mp->ports)
|
||||
goto out;
|
||||
@ -512,6 +511,27 @@ static bool br_port_group_equal(struct net_bridge_port_group *p,
|
||||
return ether_addr_equal(src, p->eth_addr);
|
||||
}
|
||||
|
||||
void br_multicast_host_join(struct net_bridge_mdb_entry *mp, bool notify)
|
||||
{
|
||||
if (!mp->host_joined) {
|
||||
mp->host_joined = true;
|
||||
if (notify)
|
||||
br_mdb_notify(mp->br->dev, NULL, &mp->addr,
|
||||
RTM_NEWMDB, 0);
|
||||
}
|
||||
mod_timer(&mp->timer, jiffies + mp->br->multicast_membership_interval);
|
||||
}
|
||||
|
||||
void br_multicast_host_leave(struct net_bridge_mdb_entry *mp, bool notify)
|
||||
{
|
||||
if (!mp->host_joined)
|
||||
return;
|
||||
|
||||
mp->host_joined = false;
|
||||
if (notify)
|
||||
br_mdb_notify(mp->br->dev, NULL, &mp->addr, RTM_DELMDB, 0);
|
||||
}
|
||||
|
||||
static int br_multicast_add_group(struct net_bridge *br,
|
||||
struct net_bridge_port *port,
|
||||
struct br_ip *group,
|
||||
@ -534,11 +554,7 @@ static int br_multicast_add_group(struct net_bridge *br,
|
||||
goto err;
|
||||
|
||||
if (!port) {
|
||||
if (!mp->host_joined) {
|
||||
mp->host_joined = true;
|
||||
br_mdb_notify(br->dev, NULL, &mp->addr, RTM_NEWMDB, 0);
|
||||
}
|
||||
mod_timer(&mp->timer, now + br->multicast_membership_interval);
|
||||
br_multicast_host_join(mp, true);
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
@ -702,6 +702,8 @@ void br_multicast_get_stats(const struct net_bridge *br,
|
||||
struct br_mcast_stats *dest);
|
||||
void br_mdb_init(void);
|
||||
void br_mdb_uninit(void);
|
||||
void br_multicast_host_join(struct net_bridge_mdb_entry *mp, bool notify);
|
||||
void br_multicast_host_leave(struct net_bridge_mdb_entry *mp, bool notify);
|
||||
|
||||
#define mlock_dereference(X, br) \
|
||||
rcu_dereference_protected(X, lockdep_is_held(&br->multicast_lock))
|
||||
|
Loading…
Reference in New Issue
Block a user