mirror of
https://github.com/torvalds/linux.git
synced 2026-10-07 19:16:02 +02: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_fdb_get = br_fdb_get,
|
||||||
.ndo_mdb_add = br_mdb_add,
|
.ndo_mdb_add = br_mdb_add,
|
||||||
.ndo_mdb_del = br_mdb_del,
|
.ndo_mdb_del = br_mdb_del,
|
||||||
|
.ndo_mdb_del_bulk = br_mdb_del_bulk,
|
||||||
.ndo_mdb_dump = br_mdb_dump,
|
.ndo_mdb_dump = br_mdb_dump,
|
||||||
.ndo_mdb_get = br_mdb_get,
|
.ndo_mdb_get = br_mdb_get,
|
||||||
.ndo_bridge_getlink = br_getlink,
|
.ndo_bridge_getlink = br_getlink,
|
||||||
|
|
|
||||||
|
|
@ -1412,6 +1412,139 @@ int br_mdb_del(struct net_device *dev, struct nlattr *tb[],
|
||||||
return err;
|
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] = {
|
static const struct nla_policy br_mdbe_attrs_get_pol[MDBE_ATTR_MAX + 1] = {
|
||||||
[MDBE_ATTR_SOURCE] = NLA_POLICY_RANGE(NLA_BINARY,
|
[MDBE_ATTR_SOURCE] = NLA_POLICY_RANGE(NLA_BINARY,
|
||||||
sizeof(struct in_addr),
|
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);
|
struct netlink_ext_ack *extack);
|
||||||
int br_mdb_del(struct net_device *dev, struct nlattr *tb[],
|
int br_mdb_del(struct net_device *dev, struct nlattr *tb[],
|
||||||
struct netlink_ext_ack *extack);
|
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,
|
int br_mdb_dump(struct net_device *dev, struct sk_buff *skb,
|
||||||
struct netlink_callback *cb);
|
struct netlink_callback *cb);
|
||||||
int br_mdb_get(struct net_device *dev, struct nlattr *tb[], u32 portid, u32 seq,
|
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;
|
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,
|
static inline int br_mdb_dump(struct net_device *dev, struct sk_buff *skb,
|
||||||
struct netlink_callback *cb)
|
struct netlink_callback *cb)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user