diff options
author | Yevgeny Petrilin <yevgenyp@mellanox.co.il> | 2014-07-16 11:57:47 +0300 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-07-16 23:26:24 -0700 |
commit | 0d7869acb2f30b64e4fb782b5df309e2287c2e1f (patch) | |
tree | 385addfeb688d50b7653e1479e260645aa6aa932 /drivers/net/ethernet/mellanox/mlx4/mcg.c | |
parent | 498044bb2ba39a6fb12c26298c697d5cd9b7378e (diff) |
net/mlx4_core: Fix leakage of SW multicast entries
When removing multicast address in B0 steering mode there is
a bug in cases where there is a single QP registered for the address,
and this QP is also promiscuous. In such cases the entry wouldn't be
deleted from the SW structure representing all Ethernet MCG entries,
but would be removed in HW. This way when driver goes to remove it
from SW and HW structures the HW deletion fails.
Moreover the same index could later be used for registering
different address, which can be Infiniband.
Signed-off-by: Yevgeny Petrilin <yevgenyp@mellanox.co.il>
Signed-off-by: Eugenia Emantayev <eugenia@mellanox.com>
Signed-off-by: Amir Vadai <amirv@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethernet/mellanox/mlx4/mcg.c')
-rw-r--r-- | drivers/net/ethernet/mellanox/mlx4/mcg.c | 14 |
1 files changed, 13 insertions, 1 deletions
diff --git a/drivers/net/ethernet/mellanox/mlx4/mcg.c b/drivers/net/ethernet/mellanox/mlx4/mcg.c index 4c36def8e10..14a40719347 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mcg.c +++ b/drivers/net/ethernet/mellanox/mlx4/mcg.c @@ -363,8 +363,20 @@ static bool can_remove_steering_entry(struct mlx4_dev *dev, u8 port, ret = true; list_for_each_entry_safe(entry, tmp_entry, &s_steer->steer_entries[steer], list) { if (entry->index == index) { - if (list_empty(&entry->duplicates)) { + if (list_empty(&entry->duplicates) || + members_count == 1) { + struct mlx4_promisc_qp *pqp, *tmp_pqp; + /* If there is only 1 entry in duplicates then + * this is the QP we want to delete, going over + * the list and deleting the entry. + */ list_del(&entry->list); + list_for_each_entry_safe(pqp, tmp_pqp, + &entry->duplicates, + list) { + list_del(&pqp->list); + kfree(pqp); + } kfree(entry); } else { /* This entry contains duplicates so it shouldn't be removed */ |