@@ -53,6 +53,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_rss.c
SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_mr.c
SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_flow.c
SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_socket.c
+SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_ipsec.c
# Basic CFLAGS.
CFLAGS += -O3
@@ -57,6 +57,7 @@
#include <rte_bus_pci.h>
#include <rte_common.h>
#include <rte_kvargs.h>
+#include <rte_security.h>
#include "mlx5.h"
#include "mlx5_utils.h"
@@ -114,6 +115,9 @@
MLX5DV_CONTEXT_XFRM_FLAGS_ESP_AES_GCM_SPI_RSS_ONLY)
#endif
+/* Dev ops structure defined in mlx5_ipsec.c */
+extern const struct rte_security_ops mlx5_security_ops;
+
struct mlx5_args {
int cqe_comp;
int txq_inline;
@@ -942,6 +946,14 @@ mlx5_pci_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
mlx5dv_set_context_attr(ctx, MLX5DV_CTX_ATTR_BUF_ALLOCATORS,
(void *)((uintptr_t)&alctr));
+ if (priv->ipsec_en) {
+ priv->security = (struct rte_security_ctx){
+ .device = (void *)eth_dev,
+ .ops = &mlx5_security_ops,
+ .sess_cnt = 0,
+ };
+ eth_dev->security_ctx = &priv->security;
+ }
/* Bring Ethernet device up. */
DEBUG("forcing Ethernet interface up");
priv_set_flags(priv, ~IFF_UP, IFF_UP);
@@ -58,6 +58,7 @@
#include <rte_interrupts.h>
#include <rte_errno.h>
#include <rte_flow.h>
+#include <rte_security.h>
#include "mlx5_utils.h"
#include "mlx5_rxtx.h"
@@ -150,6 +151,7 @@ struct priv {
rte_spinlock_t lock; /* Lock for control functions. */
int primary_socket; /* Unix socket for primary process. */
struct rte_intr_handle intr_handle_socket; /* Interrupt handler. */
+ struct rte_security_ctx security; /* Security context. */
};
/**
new file mode 100644
@@ -0,0 +1,322 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright 2017 Mellanox.
+ * Copyright 2017 6WIND S.A.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of 6WIND S.A. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* Verbs header. */
+/* ISO C doesn't support unnamed structs/unions, disabling -pedantic. */
+#ifdef PEDANTIC
+#pragma GCC diagnostic ignored "-Wpedantic"
+#endif
+#include <infiniband/verbs.h>
+#include <infiniband/mlx5dv.h>
+#ifdef PEDANTIC
+#pragma GCC diagnostic error "-Wpedantic"
+#endif
+
+#include <rte_malloc.h>
+#include <rte_security.h>
+#include <rte_cryptodev.h>
+#include <rte_security_driver.h>
+
+#include "mlx5.h"
+#include "mlx5_utils.h"
+#include "mlx5_autoconf.h"
+
+#ifdef HAVE_IBV_IPSEC_SUPPORT
+#define MLX5_IPSEC_SUPPORT_ERROR(cond) \
+ static_assert((cond), "Wrong verbs.h version for IPsec support," \
+ " please contact Mellanox")
+
+/* Extra verifications, this API is not unstreamed yet. */
+MLX5_IPSEC_SUPPORT_ERROR(MLX5DV_CONTEXT_XFRM_FLAGS_ESP_AES_GCM_REQ_METADATA ==
+ 1u << 0);
+MLX5_IPSEC_SUPPORT_ERROR(MLX5DV_CONTEXT_XFRM_FLAGS_ESP_AES_GCM_RX == 1u << 1);
+MLX5_IPSEC_SUPPORT_ERROR(MLX5DV_CONTEXT_XFRM_FLAGS_ESP_AES_GCM_TX == 1u << 2);
+MLX5_IPSEC_SUPPORT_ERROR(MLX5DV_CONTEXT_XFRM_FLAGS_ESP_AES_GCM_SPI_RSS_ONLY ==
+ 1u << 3);
+#endif
+
+/* Security session. */
+struct mlx5_security_session {
+ struct rte_security_ipsec_xform ipsec_xform;
+ struct rte_eth_dev *dev;
+ struct ibv_action_xfrm *ibv_action_xfrm;
+};
+
+/** MLX5 Crypto capabilities. */
+struct rte_cryptodev_capabilities mlx5_crypto_capabilities[] = {
+ /* AES GCM (128-bit) */
+ {
+ .op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+ .sym = {
+ .xform_type = RTE_CRYPTO_SYM_XFORM_AEAD,
+ .aead = {
+ .algo = RTE_CRYPTO_AEAD_AES_GCM,
+ .block_size = 16,
+ .key_size = {
+ .min = 16,
+ .max = 16,
+ .increment = 0,
+ },
+ .digest_size = {
+ .min = 16,
+ .max = 16,
+ .increment = 0,
+ },
+ .aad_size = {
+ .min = 8,
+ .max = 8,
+ .increment = 0,
+ },
+ .iv_size = {
+ .min = 12,
+ .max = 12,
+ .increment = 0,
+ },
+ },
+ },
+ },
+ /* AES GCM (256-bit) */
+ {
+ .op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+ .sym = {
+ .xform_type = RTE_CRYPTO_SYM_XFORM_AEAD,
+ .aead = {
+ .algo = RTE_CRYPTO_AEAD_AES_GCM,
+ .block_size = 16,
+ .key_size = {
+ .min = 32,
+ .max = 32,
+ .increment = 0,
+ },
+ .digest_size = {
+ .min = 16,
+ .max = 16,
+ .increment = 0,
+ },
+ .aad_size = {
+ .min = 8,
+ .max = 8,
+ .increment = 0,
+ },
+ .iv_size = {
+ .min = 12,
+ .max = 12,
+ .increment = 0,
+ },
+ },
+ },
+ },
+ /* None */
+ {
+ .op = RTE_CRYPTO_OP_TYPE_UNDEFINED,
+ .sym = {
+ .xform_type = RTE_CRYPTO_SYM_XFORM_NOT_SPECIFIED
+ },
+ },
+};
+
+/** MLX5 Security capabilities. */
+static const struct rte_security_capability mlx5_security_capabilities[] = {
+#ifdef HAVE_IBV_IPSEC_SUPPORT
+ /* IPsec Inline Crypto ESP Transport Egress */
+ {
+ .action = RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO,
+ .protocol = RTE_SECURITY_PROTOCOL_IPSEC,
+ .ipsec = {
+ .proto = RTE_SECURITY_IPSEC_SA_PROTO_ESP,
+ .mode = RTE_SECURITY_IPSEC_SA_MODE_TRANSPORT,
+ .direction = RTE_SECURITY_IPSEC_SA_DIR_EGRESS,
+ .options = {0},
+ },
+ .crypto_capabilities = mlx5_crypto_capabilities,
+ .ol_flags = RTE_SECURITY_TX_HW_TRAILER_OFFLOAD,
+ },
+ /* IPsec Inline Crypto ESP Transport Ingress */
+ {
+ .action = RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO,
+ .protocol = RTE_SECURITY_PROTOCOL_IPSEC,
+ .ipsec = {
+ .proto = RTE_SECURITY_IPSEC_SA_PROTO_ESP,
+ .mode = RTE_SECURITY_IPSEC_SA_MODE_TRANSPORT,
+ .direction = RTE_SECURITY_IPSEC_SA_DIR_INGRESS,
+ .options = {0},
+ },
+ .crypto_capabilities = mlx5_crypto_capabilities,
+ .ol_flags = 0,
+ },
+ /* IPsec Inline Crypto ESP Tunnel Egress */
+ {
+ .action = RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO,
+ .protocol = RTE_SECURITY_PROTOCOL_IPSEC,
+ .ipsec = {
+ .proto = RTE_SECURITY_IPSEC_SA_PROTO_ESP,
+ .mode = RTE_SECURITY_IPSEC_SA_MODE_TUNNEL,
+ .direction = RTE_SECURITY_IPSEC_SA_DIR_EGRESS,
+ .options = {0},
+ },
+ .crypto_capabilities = mlx5_crypto_capabilities,
+ .ol_flags = RTE_SECURITY_TX_HW_TRAILER_OFFLOAD,
+ },
+ /* IPsec Inline Crypto ESP Tunnel Ingress */
+ {
+ .action = RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO,
+ .protocol = RTE_SECURITY_PROTOCOL_IPSEC,
+ .ipsec = {
+ .proto = RTE_SECURITY_IPSEC_SA_PROTO_ESP,
+ .mode = RTE_SECURITY_IPSEC_SA_MODE_TUNNEL,
+ .direction = RTE_SECURITY_IPSEC_SA_DIR_INGRESS,
+ .options = {0},
+ },
+ .crypto_capabilities = mlx5_crypto_capabilities,
+ .ol_flags = 0,
+ },
+#endif /* HAVE_IBV_IPSEC_SUPPORT */
+ {
+ .action = RTE_SECURITY_ACTION_TYPE_NONE
+ }
+};
+
+/**
+ * Security capabilities.
+ *
+ * @see rte_security_capability().
+ */
+static const struct rte_security_capability *
+mlx5_security_get_capabilities(void *dev __rte_unused)
+{
+ return mlx5_security_capabilities;
+}
+
+/**
+ * Create a security session.
+ *
+ * @see security_session_create_t().
+ */
+static int
+mlx5_security_create_session
+ (void *dev __rte_unused,
+ struct rte_security_session_conf *sess_conf __rte_unused,
+ struct rte_security_session *sess __rte_unused,
+ struct rte_mempool *mempool __rte_unused)
+{
+ int ret = -ENOTSUP;
+#ifdef HAVE_IBV_IPSEC_SUPPORT
+ struct mlx5_security_session *mlx5_sess = NULL;
+ struct priv *priv = ((struct rte_eth_dev *)dev)->data->dev_private;
+ struct ibv_action_xfrm_attr_esp_aes_gcm esp_aes_gcm;
+ struct mlx5dv_action_xfrm_attr_esp_aes_gcm mlx5_attr = {
+ .xfrm_flags = MLX5DV_ACTION_XFRM_FLAGS_REQUIRE_METADATA,
+ .comp_mask =
+ MLX5DV_ACTION_XFRM_ATTR_ESP_AES_GCM_MASK_XFRM_FLAGS,
+ };
+
+ memset(&esp_aes_gcm, 0, sizeof(esp_aes_gcm));
+ if (sess_conf->action_type != RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO) {
+ ERROR("Unknown rte security session type %d",
+ sess_conf->action_type);
+ goto out;
+ }
+ if (sess_conf->protocol != RTE_SECURITY_PROTOCOL_IPSEC) {
+ ERROR("Unknown rte security session protocol %d",
+ sess_conf->protocol);
+ goto out;
+ }
+ if (sess_conf->crypto_xform->type != RTE_CRYPTO_SYM_XFORM_AEAD) {
+ ERROR("Unsupported IPsec XFORM");
+ goto out;
+ }
+ if (sess_conf->crypto_xform->aead.algo != RTE_CRYPTO_AEAD_AES_GCM) {
+ ERROR("Unsupported IPsec AEAD algorithm");
+ goto out;
+ }
+ ret = rte_mempool_get(mempool, (void **)&mlx5_sess);
+ if (ret) {
+ ERROR("Failed to allocate security session");
+ ret = -ENOMEM;
+ goto out;
+ }
+ memcpy(&mlx5_sess->ipsec_xform, &sess_conf->ipsec,
+ sizeof(sess_conf->ipsec));
+ mlx5_sess->dev = dev;
+ set_sec_session_private_data(sess, mlx5_sess);
+ /* create action xfrm */
+ esp_aes_gcm.type = IBV_ACTION_XFRM_TYPE_ESP_AES_GCM;
+ esp_aes_gcm.key_length = sess_conf->crypto_xform->aead.key.length;
+ memcpy(esp_aes_gcm.key, sess_conf->crypto_xform->aead.key.data,
+ sess_conf->crypto_xform->aead.key.length);
+ memcpy(esp_aes_gcm.salt, &sess_conf->ipsec.salt,
+ sizeof(esp_aes_gcm.salt));
+ mlx5_sess->ibv_action_xfrm =
+ mlx5dv_create_action_xfrm_esp_aes_gcm(priv->ctx,
+ &esp_aes_gcm,
+ &mlx5_attr);
+ if (!mlx5_sess->ibv_action_xfrm) {
+ ERROR("Failed to create an action_xfrm rule");
+ ret = -EFAULT;
+ rte_free(mlx5_sess);
+ }
+out:
+#endif /* HAVE_IBV_IPSEC_SUPPORT */
+ return ret;
+}
+
+/**
+ * Destroy a security session.
+ *
+ * @see security_session_destroy_t().
+ */
+static int
+mlx5_security_destroy_session(void *dev __rte_unused,
+ struct rte_security_session *sess __rte_unused)
+{
+#ifdef HAVE_IBV_IPSEC_SUPPORT
+ struct mlx5_security_session *mlx5_sess =
+ get_sec_session_private_data(sess);
+
+ if (dev != mlx5_sess->dev) {
+ ERROR("Attempt to clear session from wrong device");
+ return -EFAULT;
+ }
+ claim_zero(ibv_destroy_action_xfrm(mlx5_sess->ibv_action_xfrm));
+ rte_free(mlx5_sess);
+ return 0;
+#endif /* HAVE_IBV_IPSEC_SUPPORT */
+ return -ENOTSUP;
+}
+
+/* Security device operations. */
+const struct rte_security_ops mlx5_security_ops = {
+ .session_create = mlx5_security_create_session,
+ .session_destroy = mlx5_security_destroy_session,
+ .capabilities_get = mlx5_security_get_capabilities,
+};