net/mlx5e: Wait for concurrent flow deletion during neigh/fib events
authorVlad Buslov <vladbu@nvidia.com>
Thu, 21 Oct 2021 15:15:10 +0000 (18:15 +0300)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 25 Nov 2021 08:48:37 +0000 (09:48 +0100)
[ Upstream commit 362980eada85b5ea691e5e0d9257a991aa7ade47 ]

Function mlx5e_take_tmp_flow() skips flows with zero reference count. This
can cause syndrome 0x179e84 when the called from neigh or route update code
and the skipped flow is not removed from the hardware by the time
underlying encap/decap resource is deleted. Add new completion
'del_hw_done' that is completed when flow is unoffloaded. This is safe to
do because flow with reference count zero needs to be detached from
encap/decap entry before its memory is deallocated, which requires taking
the encap_tbl_lock mutex that is held by the event handlers code.

Fixes: 8914add2c9e5 ("net/mlx5e: Handle FIB events to update tunnel endpoint device")
Signed-off-by: Vlad Buslov <vladbu@nvidia.com>
Reviewed-by: Roi Dayan <roid@nvidia.com>
Signed-off-by: Saeed Mahameed <saeedm@nvidia.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
drivers/net/ethernet/mellanox/mlx5/core/en/tc_priv.h
drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_encap.c
drivers/net/ethernet/mellanox/mlx5/core/en_tc.c

index d1599b7b944bf046c7cbce09f4339ce78b7a06d2..c340bf90354a0a0abc6f78d481d7b63841679d1a 100644 (file)
@@ -102,6 +102,7 @@ struct mlx5e_tc_flow {
        refcount_t refcnt;
        struct rcu_head rcu_head;
        struct completion init_done;
+       struct completion del_hw_done;
        int tunnel_id; /* the mapped tunnel id of this flow */
        struct mlx5_flow_attr *attr;
 };
index 1c44c6c345f5dc7966b26117750970621b246edc..ec0163d75dd25da09bde4de9cdc6eb8959287e9c 100644 (file)
@@ -221,8 +221,14 @@ static void mlx5e_take_tmp_flow(struct mlx5e_tc_flow *flow,
                                struct list_head *flow_list,
                                int index)
 {
-       if (IS_ERR(mlx5e_flow_get(flow)))
+       if (IS_ERR(mlx5e_flow_get(flow))) {
+               /* Flow is being deleted concurrently. Wait for it to be
+                * unoffloaded from hardware, otherwise deleting encap will
+                * fail.
+                */
+               wait_for_completion(&flow->del_hw_done);
                return;
+       }
        wait_for_completion(&flow->init_done);
 
        flow->tmp_entry_index = index;
index 129ff7e0d65cc4b04f1eb8ae96037958ce5cb80b..d2e7b099b83ab13e04ebd72fbd56841aafd3a0b4 100644 (file)
@@ -1544,6 +1544,7 @@ static void mlx5e_tc_del_fdb_flow(struct mlx5e_priv *priv,
                else
                        mlx5e_tc_unoffload_fdb_rules(esw, flow, attr);
        }
+       complete_all(&flow->del_hw_done);
 
        if (mlx5_flow_has_geneve_opt(flow))
                mlx5_geneve_tlv_option_del(priv->mdev->geneve);
@@ -4222,6 +4223,7 @@ mlx5e_alloc_flow(struct mlx5e_priv *priv, int attr_size,
        INIT_LIST_HEAD(&flow->l3_to_l2_reformat);
        refcount_set(&flow->refcnt, 1);
        init_completion(&flow->init_done);
+       init_completion(&flow->del_hw_done);
 
        *__flow = flow;
        *__parse_attr = parse_attr;