diff --git a/drivers/net/ethernet/mellanox/mlx5/core/accel/ipsec.c b/drivers/net/ethernet/mellanox/mlx5/core/accel/ipsec.c index a92cd88d369c..8a4985d8cbfe 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/accel/ipsec.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/accel/ipsec.c @@ -57,7 +57,8 @@ int mlx5_accel_ipsec_counters_read(struct mlx5_core_dev *mdev, u64 *counters, } void *mlx5_accel_esp_create_hw_context(struct mlx5_core_dev *mdev, - struct mlx5_accel_esp_xfrm *xfrm) + struct mlx5_accel_esp_xfrm *xfrm, + u32 *sa_handle) { __be32 saddr[4] = {}, daddr[4] = {}; @@ -71,7 +72,7 @@ void *mlx5_accel_esp_create_hw_context(struct mlx5_core_dev *mdev, return mlx5_fpga_ipsec_create_sa_ctx(mdev, xfrm, saddr, daddr, xfrm->attrs.spi, - xfrm->attrs.is_ipv6); + xfrm->attrs.is_ipv6, sa_handle); } void mlx5_accel_esp_free_hw_context(void *context) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/accel/ipsec.h b/drivers/net/ethernet/mellanox/mlx5/core/accel/ipsec.h index f9b8e2a041c1..e89747674712 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/accel/ipsec.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/accel/ipsec.h @@ -47,7 +47,8 @@ int mlx5_accel_ipsec_counters_read(struct mlx5_core_dev *mdev, u64 *counters, unsigned int count); void *mlx5_accel_esp_create_hw_context(struct mlx5_core_dev *mdev, - struct mlx5_accel_esp_xfrm *xfrm); + struct mlx5_accel_esp_xfrm *xfrm, + u32 *sa_handle); void mlx5_accel_esp_free_hw_context(void *context); int mlx5_accel_ipsec_init(struct mlx5_core_dev *mdev); @@ -60,7 +61,8 @@ void mlx5_accel_ipsec_cleanup(struct mlx5_core_dev *mdev); static inline void * mlx5_accel_esp_create_hw_context(struct mlx5_core_dev *mdev, - struct mlx5_accel_esp_xfrm *xfrm) + struct mlx5_accel_esp_xfrm *xfrm, + u32 *sa_handle) { return NULL; } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c index 9e6c2216c93e..92eb3bad4acd 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c @@ -75,18 +75,23 @@ struct xfrm_state *mlx5e_ipsec_sadb_rx_lookup(struct mlx5e_ipsec *ipsec, return ret; } -static int mlx5e_ipsec_sadb_rx_add(struct mlx5e_ipsec_sa_entry *sa_entry) +static int mlx5e_ipsec_sadb_rx_add(struct mlx5e_ipsec_sa_entry *sa_entry, + unsigned int handle) { struct mlx5e_ipsec *ipsec = sa_entry->ipsec; + struct mlx5e_ipsec_sa_entry *_sa_entry; unsigned long flags; - int ret; - ret = ida_simple_get(&ipsec->halloc, 1, 0, GFP_KERNEL); - if (ret < 0) - return ret; + rcu_read_lock(); + hash_for_each_possible_rcu(ipsec->sadb_rx, _sa_entry, hlist, handle) + if (_sa_entry->handle == handle) { + rcu_read_unlock(); + return -EEXIST; + } + rcu_read_unlock(); spin_lock_irqsave(&ipsec->sadb_rx_lock, flags); - sa_entry->handle = ret; + sa_entry->handle = handle; hash_add_rcu(ipsec->sadb_rx, &sa_entry->hlist, sa_entry->handle); spin_unlock_irqrestore(&ipsec->sadb_rx_lock, flags); @@ -103,15 +108,6 @@ static void mlx5e_ipsec_sadb_rx_del(struct mlx5e_ipsec_sa_entry *sa_entry) spin_unlock_irqrestore(&ipsec->sadb_rx_lock, flags); } -static void mlx5e_ipsec_sadb_rx_free(struct mlx5e_ipsec_sa_entry *sa_entry) -{ - struct mlx5e_ipsec *ipsec = sa_entry->ipsec; - - /* xfrm already doing sync rcu between del and free callbacks */ - - ida_simple_remove(&ipsec->halloc, sa_entry->handle); -} - static bool mlx5e_ipsec_update_esn_state(struct mlx5e_ipsec_sa_entry *sa_entry) { struct xfrm_replay_state_esn *replay_esn; @@ -292,6 +288,7 @@ static int mlx5e_xfrm_add_state(struct xfrm_state *x) struct net_device *netdev = x->xso.dev; struct mlx5_accel_esp_xfrm_attrs attrs; struct mlx5e_priv *priv; + unsigned int sa_handle; int err; priv = netdev_priv(netdev); @@ -309,20 +306,6 @@ static int mlx5e_xfrm_add_state(struct xfrm_state *x) sa_entry->x = x; sa_entry->ipsec = priv->ipsec; - /* Add the SA to handle processed incoming packets before the add SA - * completion was received - */ - if (x->xso.flags & XFRM_OFFLOAD_INBOUND) { - err = mlx5e_ipsec_sadb_rx_add(sa_entry); - if (err) { - netdev_info(netdev, "Failed adding to SADB_RX: %d\n", err); - goto err_entry; - } - } else { - sa_entry->set_iv_op = (x->props.flags & XFRM_STATE_ESN) ? - mlx5e_ipsec_set_iv_esn : mlx5e_ipsec_set_iv; - } - /* check esn */ mlx5e_ipsec_update_esn_state(sa_entry); @@ -333,30 +316,38 @@ static int mlx5e_xfrm_add_state(struct xfrm_state *x) MLX5_ACCEL_XFRM_FLAG_REQUIRE_METADATA); if (IS_ERR(sa_entry->xfrm)) { err = PTR_ERR(sa_entry->xfrm); - goto err_sadb_rx; + goto err_sa_entry; } /* create hw context */ sa_entry->hw_context = mlx5_accel_esp_create_hw_context(priv->mdev, - sa_entry->xfrm); + sa_entry->xfrm, + &sa_handle); if (IS_ERR(sa_entry->hw_context)) { err = PTR_ERR(sa_entry->hw_context); goto err_xfrm; } + if (x->xso.flags & XFRM_OFFLOAD_INBOUND) { + err = mlx5e_ipsec_sadb_rx_add(sa_entry, sa_handle); + if (err) + goto err_hw_ctx; + } else { + sa_entry->set_iv_op = (x->props.flags & XFRM_STATE_ESN) ? + mlx5e_ipsec_set_iv_esn : mlx5e_ipsec_set_iv; + } + x->xso.offload_handle = (unsigned long)sa_entry; goto out; +err_hw_ctx: + mlx5_accel_esp_free_hw_context(sa_entry->hw_context); err_xfrm: mlx5_accel_esp_destroy_xfrm(sa_entry->xfrm); -err_sadb_rx: - if (x->xso.flags & XFRM_OFFLOAD_INBOUND) { - mlx5e_ipsec_sadb_rx_del(sa_entry); - mlx5e_ipsec_sadb_rx_free(sa_entry); - } -err_entry: +err_sa_entry: kfree(sa_entry); + out: return err; } @@ -385,9 +376,6 @@ static void mlx5e_xfrm_free_state(struct xfrm_state *x) mlx5_accel_esp_destroy_xfrm(sa_entry->xfrm); } - if (x->xso.flags & XFRM_OFFLOAD_INBOUND) - mlx5e_ipsec_sadb_rx_free(sa_entry); - kfree(sa_entry); } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fpga/ipsec.c b/drivers/net/ethernet/mellanox/mlx5/core/fpga/ipsec.c index c8736b6b4172..0604216eb94f 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fpga/ipsec.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fpga/ipsec.c @@ -65,6 +65,7 @@ struct mlx5_fpga_esp_xfrm; struct mlx5_fpga_ipsec_sa_ctx { struct rhash_head hash; struct mlx5_ifc_fpga_ipsec_sa hw_sa; + u32 sa_handle; struct mlx5_core_dev *dev; struct mlx5_fpga_esp_xfrm *fpga_xfrm; }; @@ -119,6 +120,8 @@ struct mlx5_fpga_ipsec { */ struct rb_root rules_rb; struct mutex rules_rb_lock; /* rules lock */ + + struct ida halloc; }; static bool mlx5_fpga_is_ipsec_device(struct mlx5_core_dev *mdev) @@ -666,7 +669,8 @@ void *mlx5_fpga_ipsec_create_sa_ctx(struct mlx5_core_dev *mdev, struct mlx5_accel_esp_xfrm *accel_xfrm, const __be32 saddr[4], const __be32 daddr[4], - const __be32 spi, bool is_ipv6) + const __be32 spi, bool is_ipv6, + u32 *sa_handle) { struct mlx5_fpga_ipsec_sa_ctx *sa_ctx; struct mlx5_fpga_esp_xfrm *fpga_xfrm = @@ -704,6 +708,17 @@ void *mlx5_fpga_ipsec_create_sa_ctx(struct mlx5_core_dev *mdev, goto exists; } + if (accel_xfrm->attrs.action & MLX5_ACCEL_ESP_ACTION_DECRYPT) { + err = ida_simple_get(&fipsec->halloc, 1, 0, GFP_KERNEL); + if (err < 0) { + context = ERR_PTR(err); + goto exists; + } + + sa_ctx->sa_handle = err; + if (sa_handle) + *sa_handle = sa_ctx->sa_handle; + } /* This is unbounded fpga_xfrm, try to add to hash */ mutex_lock(&fipsec->sa_hash_lock); @@ -744,7 +759,8 @@ void *mlx5_fpga_ipsec_create_sa_ctx(struct mlx5_core_dev *mdev, rhash_sa)); unlock_hash: mutex_unlock(&fipsec->sa_hash_lock); - + if (accel_xfrm->attrs.action & MLX5_ACCEL_ESP_ACTION_DECRYPT) + ida_simple_remove(&fipsec->halloc, sa_ctx->sa_handle); exists: mutex_unlock(&fpga_xfrm->lock); kfree(sa_ctx); @@ -816,7 +832,7 @@ mlx5_fpga_ipsec_fs_create_sa_ctx(struct mlx5_core_dev *mdev, /* create */ return mlx5_fpga_ipsec_create_sa_ctx(mdev, accel_xfrm, saddr, daddr, - spi, is_ipv6); + spi, is_ipv6, NULL); } static void @@ -836,6 +852,10 @@ mlx5_fpga_ipsec_release_sa_ctx(struct mlx5_fpga_ipsec_sa_ctx *sa_ctx) return; } + if (sa_ctx->fpga_xfrm->accel_xfrm.attrs.action & + MLX5_ACCEL_ESP_ACTION_DECRYPT) + ida_simple_remove(&fipsec->halloc, sa_ctx->sa_handle); + mutex_lock(&fipsec->sa_hash_lock); WARN_ON(rhashtable_remove_fast(&fipsec->sa_hash, &sa_ctx->hash, rhash_sa)); @@ -1299,6 +1319,8 @@ int mlx5_fpga_ipsec_init(struct mlx5_core_dev *mdev) goto err_destroy_hash; } + ida_init(&fdev->ipsec->halloc); + return 0; err_destroy_hash: @@ -1331,6 +1353,7 @@ void mlx5_fpga_ipsec_cleanup(struct mlx5_core_dev *mdev) if (!mlx5_fpga_is_ipsec_device(mdev)) return; + ida_destroy(&fdev->ipsec->halloc); destroy_rules_rb(&fdev->ipsec->rules_rb); rhashtable_destroy(&fdev->ipsec->sa_hash); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fpga/ipsec.h b/drivers/net/ethernet/mellanox/mlx5/core/fpga/ipsec.h index d01b1fc8e11b..9ba637f0f0f2 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fpga/ipsec.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/fpga/ipsec.h @@ -47,7 +47,8 @@ void *mlx5_fpga_ipsec_create_sa_ctx(struct mlx5_core_dev *mdev, struct mlx5_accel_esp_xfrm *accel_xfrm, const __be32 saddr[4], const __be32 daddr[4], - const __be32 spi, bool is_ipv6); + const __be32 spi, bool is_ipv6, + u32 *sa_handle); void mlx5_fpga_ipsec_delete_sa_ctx(void *context); int mlx5_fpga_ipsec_init(struct mlx5_core_dev *mdev);