mirror of
https://github.com/torvalds/linux.git
synced 2024-12-28 05:41:55 +00:00
bridge: mdb: Add MDB bulk deletion support
Implement MDB bulk deletion support in the bridge driver, allowing MDB entries to be deleted in bulk according to provided parameters. Signed-off-by: Ido Schimmel <idosch@nvidia.com> Reviewed-by: Petr Machata <petrm@nvidia.com> Acked-by: Nikolay Aleksandrov <razor@blackwall.org> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
d8e81f1311
commit
a6acb535af
@ -471,6 +471,7 @@ static const struct net_device_ops br_netdev_ops = {
|
||||
.ndo_fdb_get = br_fdb_get,
|
||||
.ndo_mdb_add = br_mdb_add,
|
||||
.ndo_mdb_del = br_mdb_del,
|
||||
.ndo_mdb_del_bulk = br_mdb_del_bulk,
|
||||
.ndo_mdb_dump = br_mdb_dump,
|
||||
.ndo_mdb_get = br_mdb_get,
|
||||
.ndo_bridge_getlink = br_getlink,
|
||||
|
@ -1412,6 +1412,139 @@ int br_mdb_del(struct net_device *dev, struct nlattr *tb[],
|
||||
return err;
|
||||
}
|
||||
|
||||
struct br_mdb_flush_desc {
|
||||
u32 port_ifindex;
|
||||
u16 vid;
|
||||
u8 rt_protocol;
|
||||
u8 state;
|
||||
u8 state_mask;
|
||||
};
|
||||
|
||||
static const struct nla_policy br_mdbe_attrs_del_bulk_pol[MDBE_ATTR_MAX + 1] = {
|
||||
[MDBE_ATTR_RTPROT] = NLA_POLICY_MIN(NLA_U8, RTPROT_STATIC),
|
||||
[MDBE_ATTR_STATE_MASK] = NLA_POLICY_MASK(NLA_U8, MDB_PERMANENT),
|
||||
};
|
||||
|
||||
static int br_mdb_flush_desc_init(struct br_mdb_flush_desc *desc,
|
||||
struct nlattr *tb[],
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct br_mdb_entry *entry = nla_data(tb[MDBA_SET_ENTRY]);
|
||||
struct nlattr *mdbe_attrs[MDBE_ATTR_MAX + 1];
|
||||
int err;
|
||||
|
||||
desc->port_ifindex = entry->ifindex;
|
||||
desc->vid = entry->vid;
|
||||
desc->state = entry->state;
|
||||
|
||||
if (!tb[MDBA_SET_ENTRY_ATTRS])
|
||||
return 0;
|
||||
|
||||
err = nla_parse_nested(mdbe_attrs, MDBE_ATTR_MAX,
|
||||
tb[MDBA_SET_ENTRY_ATTRS],
|
||||
br_mdbe_attrs_del_bulk_pol, extack);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (mdbe_attrs[MDBE_ATTR_STATE_MASK])
|
||||
desc->state_mask = nla_get_u8(mdbe_attrs[MDBE_ATTR_STATE_MASK]);
|
||||
|
||||
if (mdbe_attrs[MDBE_ATTR_RTPROT])
|
||||
desc->rt_protocol = nla_get_u8(mdbe_attrs[MDBE_ATTR_RTPROT]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void br_mdb_flush_host(struct net_bridge *br,
|
||||
struct net_bridge_mdb_entry *mp,
|
||||
const struct br_mdb_flush_desc *desc)
|
||||
{
|
||||
u8 state;
|
||||
|
||||
if (desc->port_ifindex && desc->port_ifindex != br->dev->ifindex)
|
||||
return;
|
||||
|
||||
if (desc->rt_protocol)
|
||||
return;
|
||||
|
||||
state = br_group_is_l2(&mp->addr) ? MDB_PERMANENT : 0;
|
||||
if (desc->state_mask && (state & desc->state_mask) != desc->state)
|
||||
return;
|
||||
|
||||
br_multicast_host_leave(mp, true);
|
||||
if (!mp->ports && netif_running(br->dev))
|
||||
mod_timer(&mp->timer, jiffies);
|
||||
}
|
||||
|
||||
static void br_mdb_flush_pgs(struct net_bridge *br,
|
||||
struct net_bridge_mdb_entry *mp,
|
||||
const struct br_mdb_flush_desc *desc)
|
||||
{
|
||||
struct net_bridge_port_group __rcu **pp;
|
||||
struct net_bridge_port_group *p;
|
||||
|
||||
for (pp = &mp->ports; (p = mlock_dereference(*pp, br)) != NULL;) {
|
||||
u8 state;
|
||||
|
||||
if (desc->port_ifindex &&
|
||||
desc->port_ifindex != p->key.port->dev->ifindex) {
|
||||
pp = &p->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (desc->rt_protocol && desc->rt_protocol != p->rt_protocol) {
|
||||
pp = &p->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
state = p->flags & MDB_PG_FLAGS_PERMANENT ? MDB_PERMANENT : 0;
|
||||
if (desc->state_mask &&
|
||||
(state & desc->state_mask) != desc->state) {
|
||||
pp = &p->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
br_multicast_del_pg(mp, p, pp);
|
||||
}
|
||||
}
|
||||
|
||||
static void br_mdb_flush(struct net_bridge *br,
|
||||
const struct br_mdb_flush_desc *desc)
|
||||
{
|
||||
struct net_bridge_mdb_entry *mp;
|
||||
|
||||
spin_lock_bh(&br->multicast_lock);
|
||||
|
||||
/* Safe variant is not needed because entries are removed from the list
|
||||
* upon group timer expiration or bridge deletion.
|
||||
*/
|
||||
hlist_for_each_entry(mp, &br->mdb_list, mdb_node) {
|
||||
if (desc->vid && desc->vid != mp->addr.vid)
|
||||
continue;
|
||||
|
||||
br_mdb_flush_host(br, mp, desc);
|
||||
br_mdb_flush_pgs(br, mp, desc);
|
||||
}
|
||||
|
||||
spin_unlock_bh(&br->multicast_lock);
|
||||
}
|
||||
|
||||
int br_mdb_del_bulk(struct net_device *dev, struct nlattr *tb[],
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct net_bridge *br = netdev_priv(dev);
|
||||
struct br_mdb_flush_desc desc = {};
|
||||
int err;
|
||||
|
||||
err = br_mdb_flush_desc_init(&desc, tb, extack);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
br_mdb_flush(br, &desc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct nla_policy br_mdbe_attrs_get_pol[MDBE_ATTR_MAX + 1] = {
|
||||
[MDBE_ATTR_SOURCE] = NLA_POLICY_RANGE(NLA_BINARY,
|
||||
sizeof(struct in_addr),
|
||||
|
@ -1022,6 +1022,8 @@ int br_mdb_add(struct net_device *dev, struct nlattr *tb[], u16 nlmsg_flags,
|
||||
struct netlink_ext_ack *extack);
|
||||
int br_mdb_del(struct net_device *dev, struct nlattr *tb[],
|
||||
struct netlink_ext_ack *extack);
|
||||
int br_mdb_del_bulk(struct net_device *dev, struct nlattr *tb[],
|
||||
struct netlink_ext_ack *extack);
|
||||
int br_mdb_dump(struct net_device *dev, struct sk_buff *skb,
|
||||
struct netlink_callback *cb);
|
||||
int br_mdb_get(struct net_device *dev, struct nlattr *tb[], u32 portid, u32 seq,
|
||||
@ -1430,6 +1432,12 @@ static inline int br_mdb_del(struct net_device *dev, struct nlattr *tb[],
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline int br_mdb_del_bulk(struct net_device *dev, struct nlattr *tb[],
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline int br_mdb_dump(struct net_device *dev, struct sk_buff *skb,
|
||||
struct netlink_callback *cb)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user