提交 fd372a7a 编写于 作者: D David S. Miller

Merge tag 'mlx5-updates-2018-02-28-2' of...

Merge tag 'mlx5-updates-2018-02-28-2' of git://git.kernel.org/pub/scm/linux/kernel/git/mellanox/linux

Saeed Mahameed says:

====================
mlx5-updates-2018-02-28-2 (IPSec-2)

This series follows our previous one to lay out the foundations for IPSec
in user-space and extend current kernel netdev IPSec support. As noted in
our previous pull request cover letter "mlx5-updates-2018-02-28-1 (IPSec-1)",
the IPSec mechanism will be supported through our flow steering mechanism.
Therefore, we need to change the initialization order. Furthermore, IPsec
is also supported in both egress and ingress. Since our current flow
steering is egress only, we add an empty (only implemented through FPGA
steering ops) egress namespace to handle that case. We also implement
the required flow steering callbacks and logic in our FPGA driver.

We extend the FPGA support for ESN and modifying a xfrm too. Therefore, we
add support for some new FPGA command interface that supports them. The
other required bits are added too. The new features and requirements are
advertised via cap bits.

Last but not least, we revise our driver's accel_esp API. This API will be
shared between our netdev and IB driver, so we need to have all the required
functionality from both worlds.

Regards,
Aviad and Matan
====================
Signed-off-by: NDavid S. Miller <davem@davemloft.net>
...@@ -37,24 +37,11 @@ ...@@ -37,24 +37,11 @@
#include "mlx5_core.h" #include "mlx5_core.h"
#include "fpga/ipsec.h" #include "fpga/ipsec.h"
void *mlx5_accel_ipsec_sa_cmd_exec(struct mlx5_core_dev *mdev,
struct mlx5_accel_ipsec_sa *cmd)
{
if (!MLX5_IPSEC_DEV(mdev))
return ERR_PTR(-EOPNOTSUPP);
return mlx5_fpga_ipsec_sa_cmd_exec(mdev, cmd);
}
int mlx5_accel_ipsec_sa_cmd_wait(void *ctx)
{
return mlx5_fpga_ipsec_sa_cmd_wait(ctx);
}
u32 mlx5_accel_ipsec_device_caps(struct mlx5_core_dev *mdev) u32 mlx5_accel_ipsec_device_caps(struct mlx5_core_dev *mdev)
{ {
return mlx5_fpga_ipsec_device_caps(mdev); return mlx5_fpga_ipsec_device_caps(mdev);
} }
EXPORT_SYMBOL_GPL(mlx5_accel_ipsec_device_caps);
unsigned int mlx5_accel_ipsec_counters_count(struct mlx5_core_dev *mdev) unsigned int mlx5_accel_ipsec_counters_count(struct mlx5_core_dev *mdev)
{ {
...@@ -67,6 +54,21 @@ int mlx5_accel_ipsec_counters_read(struct mlx5_core_dev *mdev, u64 *counters, ...@@ -67,6 +54,21 @@ int mlx5_accel_ipsec_counters_read(struct mlx5_core_dev *mdev, u64 *counters,
return mlx5_fpga_ipsec_counters_read(mdev, counters, count); return mlx5_fpga_ipsec_counters_read(mdev, counters, count);
} }
void *mlx5_accel_esp_create_hw_context(struct mlx5_core_dev *mdev,
struct mlx5_accel_esp_xfrm *xfrm,
const __be32 saddr[4],
const __be32 daddr[4],
const __be32 spi, bool is_ipv6)
{
return mlx5_fpga_ipsec_create_sa_ctx(mdev, xfrm, saddr, daddr,
spi, is_ipv6);
}
void mlx5_accel_esp_free_hw_context(void *context)
{
mlx5_fpga_ipsec_delete_sa_ctx(context);
}
int mlx5_accel_ipsec_init(struct mlx5_core_dev *mdev) int mlx5_accel_ipsec_init(struct mlx5_core_dev *mdev)
{ {
return mlx5_fpga_ipsec_init(mdev); return mlx5_fpga_ipsec_init(mdev);
...@@ -76,3 +78,32 @@ void mlx5_accel_ipsec_cleanup(struct mlx5_core_dev *mdev) ...@@ -76,3 +78,32 @@ void mlx5_accel_ipsec_cleanup(struct mlx5_core_dev *mdev)
{ {
mlx5_fpga_ipsec_cleanup(mdev); mlx5_fpga_ipsec_cleanup(mdev);
} }
struct mlx5_accel_esp_xfrm *
mlx5_accel_esp_create_xfrm(struct mlx5_core_dev *mdev,
const struct mlx5_accel_esp_xfrm_attrs *attrs,
u32 flags)
{
struct mlx5_accel_esp_xfrm *xfrm;
xfrm = mlx5_fpga_esp_create_xfrm(mdev, attrs, flags);
if (IS_ERR(xfrm))
return xfrm;
xfrm->mdev = mdev;
return xfrm;
}
EXPORT_SYMBOL_GPL(mlx5_accel_esp_create_xfrm);
void mlx5_accel_esp_destroy_xfrm(struct mlx5_accel_esp_xfrm *xfrm)
{
mlx5_fpga_esp_destroy_xfrm(xfrm);
}
EXPORT_SYMBOL_GPL(mlx5_accel_esp_destroy_xfrm);
int mlx5_accel_esp_modify_xfrm(struct mlx5_accel_esp_xfrm *xfrm,
const struct mlx5_accel_esp_xfrm_attrs *attrs)
{
return mlx5_fpga_esp_modify_xfrm(xfrm, attrs);
}
EXPORT_SYMBOL_GPL(mlx5_accel_esp_modify_xfrm);
...@@ -35,88 +35,24 @@ ...@@ -35,88 +35,24 @@
#define __MLX5_ACCEL_IPSEC_H__ #define __MLX5_ACCEL_IPSEC_H__
#include <linux/mlx5/driver.h> #include <linux/mlx5/driver.h>
#include <linux/mlx5/accel.h>
#ifdef CONFIG_MLX5_ACCEL #ifdef CONFIG_MLX5_ACCEL
enum {
MLX5_ACCEL_IPSEC_DEVICE = BIT(1),
MLX5_ACCEL_IPSEC_IPV6 = BIT(2),
MLX5_ACCEL_IPSEC_ESP = BIT(3),
MLX5_ACCEL_IPSEC_LSO = BIT(4),
};
#define MLX5_IPSEC_SADB_IP_AH BIT(7)
#define MLX5_IPSEC_SADB_IP_ESP BIT(6)
#define MLX5_IPSEC_SADB_SA_VALID BIT(5)
#define MLX5_IPSEC_SADB_SPI_EN BIT(4)
#define MLX5_IPSEC_SADB_DIR_SX BIT(3)
#define MLX5_IPSEC_SADB_IPV6 BIT(2)
enum {
MLX5_IPSEC_CMD_ADD_SA = 0,
MLX5_IPSEC_CMD_DEL_SA = 1,
};
enum mlx5_accel_ipsec_enc_mode {
MLX5_IPSEC_SADB_MODE_NONE = 0,
MLX5_IPSEC_SADB_MODE_AES_GCM_128_AUTH_128 = 1,
MLX5_IPSEC_SADB_MODE_AES_GCM_256_AUTH_128 = 3,
};
#define MLX5_IPSEC_DEV(mdev) (mlx5_accel_ipsec_device_caps(mdev) & \ #define MLX5_IPSEC_DEV(mdev) (mlx5_accel_ipsec_device_caps(mdev) & \
MLX5_ACCEL_IPSEC_DEVICE) MLX5_ACCEL_IPSEC_CAP_DEVICE)
struct mlx5_accel_ipsec_sa {
__be32 cmd;
u8 key_enc[32];
u8 key_auth[32];
__be32 sip[4];
__be32 dip[4];
union {
struct {
__be32 reserved;
u8 salt_iv[8];
__be32 salt;
} __packed gcm;
struct {
u8 salt[16];
} __packed cbc;
};
__be32 spi;
__be32 sw_sa_handle;
__be16 tfclen;
u8 enc_mode;
u8 sip_masklen;
u8 dip_masklen;
u8 flags;
u8 reserved[2];
} __packed;
/**
* mlx5_accel_ipsec_sa_cmd_exec - Execute an IPSec SADB command
* @mdev: mlx5 device
* @cmd: command to execute
* May be called from atomic context. Returns context pointer, or error
* Caller must eventually call mlx5_accel_ipsec_sa_cmd_wait from non-atomic
* context, to cleanup the context pointer
*/
void *mlx5_accel_ipsec_sa_cmd_exec(struct mlx5_core_dev *mdev,
struct mlx5_accel_ipsec_sa *cmd);
/**
* mlx5_accel_ipsec_sa_cmd_wait - Wait for command execution completion
* @context: Context pointer returned from call to mlx5_accel_ipsec_sa_cmd_exec
* Sleeps (killable) until command execution is complete.
* Returns the command result, or -EINTR if killed
*/
int mlx5_accel_ipsec_sa_cmd_wait(void *context);
u32 mlx5_accel_ipsec_device_caps(struct mlx5_core_dev *mdev);
unsigned int mlx5_accel_ipsec_counters_count(struct mlx5_core_dev *mdev); unsigned int mlx5_accel_ipsec_counters_count(struct mlx5_core_dev *mdev);
int mlx5_accel_ipsec_counters_read(struct mlx5_core_dev *mdev, u64 *counters, int mlx5_accel_ipsec_counters_read(struct mlx5_core_dev *mdev, u64 *counters,
unsigned int count); unsigned int count);
void *mlx5_accel_esp_create_hw_context(struct mlx5_core_dev *mdev,
struct mlx5_accel_esp_xfrm *xfrm,
const __be32 saddr[4],
const __be32 daddr[4],
const __be32 spi, bool is_ipv6);
void mlx5_accel_esp_free_hw_context(void *context);
int mlx5_accel_ipsec_init(struct mlx5_core_dev *mdev); int mlx5_accel_ipsec_init(struct mlx5_core_dev *mdev);
void mlx5_accel_ipsec_cleanup(struct mlx5_core_dev *mdev); void mlx5_accel_ipsec_cleanup(struct mlx5_core_dev *mdev);
...@@ -124,6 +60,20 @@ void mlx5_accel_ipsec_cleanup(struct mlx5_core_dev *mdev); ...@@ -124,6 +60,20 @@ void mlx5_accel_ipsec_cleanup(struct mlx5_core_dev *mdev);
#define MLX5_IPSEC_DEV(mdev) false #define MLX5_IPSEC_DEV(mdev) false
static inline void *
mlx5_accel_esp_create_hw_context(struct mlx5_core_dev *mdev,
struct mlx5_accel_esp_xfrm *xfrm,
const __be32 saddr[4],
const __be32 daddr[4],
const __be32 spi, bool is_ipv6)
{
return NULL;
}
static inline void mlx5_accel_esp_free_hw_context(void *context)
{
}
static inline int mlx5_accel_ipsec_init(struct mlx5_core_dev *mdev) static inline int mlx5_accel_ipsec_init(struct mlx5_core_dev *mdev)
{ {
return 0; return 0;
......
...@@ -109,8 +109,7 @@ int mlx5_core_create_cq(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq, ...@@ -109,8 +109,7 @@ int mlx5_core_create_cq(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq,
cq->cons_index = 0; cq->cons_index = 0;
cq->arm_sn = 0; cq->arm_sn = 0;
cq->eq = eq; cq->eq = eq;
refcount_set(&cq->refcount, 0); refcount_set(&cq->refcount, 1);
mlx5_cq_hold(cq);
init_completion(&cq->free); init_completion(&cq->free);
if (!cq->comp) if (!cq->comp)
cq->comp = mlx5_add_cq_to_tasklet; cq->comp = mlx5_add_cq_to_tasklet;
......
...@@ -38,17 +38,24 @@ ...@@ -38,17 +38,24 @@
#include <linux/module.h> #include <linux/module.h>
#include "en.h" #include "en.h"
#include "accel/ipsec.h"
#include "en_accel/ipsec.h" #include "en_accel/ipsec.h"
#include "en_accel/ipsec_rxtx.h" #include "en_accel/ipsec_rxtx.h"
struct mlx5e_ipsec_sa_entry {
struct hlist_node hlist; /* Item in SADB_RX hashtable */ static struct mlx5e_ipsec_sa_entry *to_ipsec_sa_entry(struct xfrm_state *x)
unsigned int handle; /* Handle in SADB_RX */ {
struct xfrm_state *x; struct mlx5e_ipsec_sa_entry *sa;
struct mlx5e_ipsec *ipsec;
void *context; if (!x)
}; return NULL;
sa = (struct mlx5e_ipsec_sa_entry *)x->xso.offload_handle;
if (!sa)
return NULL;
WARN_ON(sa->x != x);
return sa;
}
struct xfrm_state *mlx5e_ipsec_sadb_rx_lookup(struct mlx5e_ipsec *ipsec, struct xfrm_state *mlx5e_ipsec_sadb_rx_lookup(struct mlx5e_ipsec *ipsec,
unsigned int handle) unsigned int handle)
...@@ -105,78 +112,93 @@ static void mlx5e_ipsec_sadb_rx_free(struct mlx5e_ipsec_sa_entry *sa_entry) ...@@ -105,78 +112,93 @@ static void mlx5e_ipsec_sadb_rx_free(struct mlx5e_ipsec_sa_entry *sa_entry)
ida_simple_remove(&ipsec->halloc, sa_entry->handle); ida_simple_remove(&ipsec->halloc, sa_entry->handle);
} }
static enum mlx5_accel_ipsec_enc_mode mlx5e_ipsec_enc_mode(struct xfrm_state *x) static bool mlx5e_ipsec_update_esn_state(struct mlx5e_ipsec_sa_entry *sa_entry)
{ {
unsigned int key_len = (x->aead->alg_key_len + 7) / 8 - 4; struct xfrm_replay_state_esn *replay_esn;
u32 seq_bottom;
switch (key_len) { u8 overlap;
case 16: u32 *esn;
return MLX5_IPSEC_SADB_MODE_AES_GCM_128_AUTH_128;
case 32: if (!(sa_entry->x->props.flags & XFRM_STATE_ESN)) {
return MLX5_IPSEC_SADB_MODE_AES_GCM_256_AUTH_128; sa_entry->esn_state.trigger = 0;
default: return false;
netdev_warn(x->xso.dev, "Bad key len: %d for alg %s\n",
key_len, x->aead->alg_name);
return -1;
} }
replay_esn = sa_entry->x->replay_esn;
seq_bottom = replay_esn->seq - replay_esn->replay_window + 1;
overlap = sa_entry->esn_state.overlap;
sa_entry->esn_state.esn = xfrm_replay_seqhi(sa_entry->x,
htonl(seq_bottom));
esn = &sa_entry->esn_state.esn;
sa_entry->esn_state.trigger = 1;
if (unlikely(overlap && seq_bottom < MLX5E_IPSEC_ESN_SCOPE_MID)) {
++(*esn);
sa_entry->esn_state.overlap = 0;
return true;
} else if (unlikely(!overlap &&
(seq_bottom >= MLX5E_IPSEC_ESN_SCOPE_MID))) {
sa_entry->esn_state.overlap = 1;
return true;
}
return false;
} }
static void mlx5e_ipsec_build_hw_sa(u32 op, struct mlx5e_ipsec_sa_entry *sa_entry, static void
struct mlx5_accel_ipsec_sa *hw_sa) mlx5e_ipsec_build_accel_xfrm_attrs(struct mlx5e_ipsec_sa_entry *sa_entry,
struct mlx5_accel_esp_xfrm_attrs *attrs)
{ {
struct xfrm_state *x = sa_entry->x; struct xfrm_state *x = sa_entry->x;
struct aes_gcm_keymat *aes_gcm = &attrs->keymat.aes_gcm;
struct aead_geniv_ctx *geniv_ctx; struct aead_geniv_ctx *geniv_ctx;
unsigned int crypto_data_len;
struct crypto_aead *aead; struct crypto_aead *aead;
unsigned int key_len; unsigned int crypto_data_len, key_len;
int ivsize; int ivsize;
memset(hw_sa, 0, sizeof(*hw_sa)); memset(attrs, 0, sizeof(*attrs));
if (op == MLX5_IPSEC_CMD_ADD_SA) {
crypto_data_len = (x->aead->alg_key_len + 7) / 8;
key_len = crypto_data_len - 4; /* 4 bytes salt at end */
aead = x->data;
geniv_ctx = crypto_aead_ctx(aead);
ivsize = crypto_aead_ivsize(aead);
memcpy(&hw_sa->key_enc, x->aead->alg_key, key_len);
/* Duplicate 128 bit key twice according to HW layout */
if (key_len == 16)
memcpy(&hw_sa->key_enc[16], x->aead->alg_key, key_len);
memcpy(&hw_sa->gcm.salt_iv, geniv_ctx->salt, ivsize);
hw_sa->gcm.salt = *((__be32 *)(x->aead->alg_key + key_len));
}
hw_sa->cmd = htonl(op); /* key */
hw_sa->flags |= MLX5_IPSEC_SADB_SA_VALID | MLX5_IPSEC_SADB_SPI_EN; crypto_data_len = (x->aead->alg_key_len + 7) / 8;
if (x->props.family == AF_INET) { key_len = crypto_data_len - 4; /* 4 bytes salt at end */
hw_sa->sip[3] = x->props.saddr.a4;
hw_sa->dip[3] = x->id.daddr.a4; memcpy(aes_gcm->aes_key, x->aead->alg_key, key_len);
hw_sa->sip_masklen = 32; aes_gcm->key_len = key_len * 8;
hw_sa->dip_masklen = 32;
} else { /* salt and seq_iv */
memcpy(hw_sa->sip, x->props.saddr.a6, sizeof(hw_sa->sip)); aead = x->data;
memcpy(hw_sa->dip, x->id.daddr.a6, sizeof(hw_sa->dip)); geniv_ctx = crypto_aead_ctx(aead);
hw_sa->sip_masklen = 128; ivsize = crypto_aead_ivsize(aead);
hw_sa->dip_masklen = 128; memcpy(&aes_gcm->seq_iv, &geniv_ctx->salt, ivsize);
hw_sa->flags |= MLX5_IPSEC_SADB_IPV6; memcpy(&aes_gcm->salt, x->aead->alg_key + key_len,
} sizeof(aes_gcm->salt));
hw_sa->spi = x->id.spi;
hw_sa->sw_sa_handle = htonl(sa_entry->handle); /* iv len */
switch (x->id.proto) { aes_gcm->icv_len = x->aead->alg_icv_len;
case IPPROTO_ESP:
hw_sa->flags |= MLX5_IPSEC_SADB_IP_ESP; /* esn */
break; if (sa_entry->esn_state.trigger) {
case IPPROTO_AH: attrs->flags |= MLX5_ACCEL_ESP_FLAGS_ESN_TRIGGERED;
hw_sa->flags |= MLX5_IPSEC_SADB_IP_AH; attrs->esn = sa_entry->esn_state.esn;
break; if (sa_entry->esn_state.overlap)
default: attrs->flags |= MLX5_ACCEL_ESP_FLAGS_ESN_STATE_OVERLAP;
break;
} }
hw_sa->enc_mode = mlx5e_ipsec_enc_mode(x);
if (!(x->xso.flags & XFRM_OFFLOAD_INBOUND)) /* rx handle */
hw_sa->flags |= MLX5_IPSEC_SADB_DIR_SX; attrs->sa_handle = sa_entry->handle;
/* algo type */
attrs->keymat_type = MLX5_ACCEL_ESP_KEYMAT_AES_GCM;
/* action */
attrs->action = (!(x->xso.flags & XFRM_OFFLOAD_INBOUND)) ?
MLX5_ACCEL_ESP_ACTION_ENCRYPT :
MLX5_ACCEL_ESP_ACTION_DECRYPT;
/* flags */
attrs->flags |= (x->props.mode == XFRM_MODE_TRANSPORT) ?
MLX5_ACCEL_ESP_FLAGS_TRANSPORT :
MLX5_ACCEL_ESP_FLAGS_TUNNEL;
} }
static inline int mlx5e_xfrm_validate_state(struct xfrm_state *x) static inline int mlx5e_xfrm_validate_state(struct xfrm_state *x)
...@@ -198,7 +220,9 @@ static inline int mlx5e_xfrm_validate_state(struct xfrm_state *x) ...@@ -198,7 +220,9 @@ static inline int mlx5e_xfrm_validate_state(struct xfrm_state *x)
netdev_info(netdev, "Cannot offload compressed xfrm states\n"); netdev_info(netdev, "Cannot offload compressed xfrm states\n");
return -EINVAL; return -EINVAL;
} }
if (x->props.flags & XFRM_STATE_ESN) { if (x->props.flags & XFRM_STATE_ESN &&
!(mlx5_accel_ipsec_device_caps(priv->mdev) &
MLX5_ACCEL_IPSEC_CAP_ESN)) {
netdev_info(netdev, "Cannot offload ESN xfrm states\n"); netdev_info(netdev, "Cannot offload ESN xfrm states\n");
return -EINVAL; return -EINVAL;
} }
...@@ -246,7 +270,8 @@ static inline int mlx5e_xfrm_validate_state(struct xfrm_state *x) ...@@ -246,7 +270,8 @@ static inline int mlx5e_xfrm_validate_state(struct xfrm_state *x)
return -EINVAL; return -EINVAL;
} }
if (x->props.family == AF_INET6 && if (x->props.family == AF_INET6 &&
!(mlx5_accel_ipsec_device_caps(priv->mdev) & MLX5_ACCEL_IPSEC_IPV6)) { !(mlx5_accel_ipsec_device_caps(priv->mdev) &
MLX5_ACCEL_IPSEC_CAP_IPV6)) {
netdev_info(netdev, "IPv6 xfrm state offload is not supported by this device\n"); netdev_info(netdev, "IPv6 xfrm state offload is not supported by this device\n");
return -EINVAL; return -EINVAL;
} }
...@@ -257,9 +282,10 @@ static int mlx5e_xfrm_add_state(struct xfrm_state *x) ...@@ -257,9 +282,10 @@ static int mlx5e_xfrm_add_state(struct xfrm_state *x)
{ {
struct mlx5e_ipsec_sa_entry *sa_entry = NULL; struct mlx5e_ipsec_sa_entry *sa_entry = NULL;
struct net_device *netdev = x->xso.dev; struct net_device *netdev = x->xso.dev;
struct mlx5_accel_ipsec_sa hw_sa; struct mlx5_accel_esp_xfrm_attrs attrs;
struct mlx5e_priv *priv; struct mlx5e_priv *priv;
void *context; __be32 saddr[4] = {0}, daddr[4] = {0}, spi;
bool is_ipv6 = false;
int err; int err;
priv = netdev_priv(netdev); priv = netdev_priv(netdev);
...@@ -286,22 +312,49 @@ static int mlx5e_xfrm_add_state(struct xfrm_state *x) ...@@ -286,22 +312,49 @@ static int mlx5e_xfrm_add_state(struct xfrm_state *x)
netdev_info(netdev, "Failed adding to SADB_RX: %d\n", err); netdev_info(netdev, "Failed adding to SADB_RX: %d\n", err);
goto err_entry; goto err_entry;
} }
} else {
sa_entry->set_iv_op = (x->props.flags & XFRM_STATE_ESN) ?
mlx5e_ipsec_set_iv_esn : mlx5e_ipsec_set_iv;
} }
mlx5e_ipsec_build_hw_sa(MLX5_IPSEC_CMD_ADD_SA, sa_entry, &hw_sa); /* check esn */
context = mlx5_accel_ipsec_sa_cmd_exec(sa_entry->ipsec->en_priv->mdev, &hw_sa); mlx5e_ipsec_update_esn_state(sa_entry);
if (IS_ERR(context)) {
err = PTR_ERR(context); /* create xfrm */
mlx5e_ipsec_build_accel_xfrm_attrs(sa_entry, &attrs);
sa_entry->xfrm =
mlx5_accel_esp_create_xfrm(priv->mdev, &attrs,
MLX5_ACCEL_XFRM_FLAG_REQUIRE_METADATA);
if (IS_ERR(sa_entry->xfrm)) {
err = PTR_ERR(sa_entry->xfrm);
goto err_sadb_rx; goto err_sadb_rx;
} }
err = mlx5_accel_ipsec_sa_cmd_wait(context); /* create hw context */
if (err) if (x->props.family == AF_INET) {
goto err_sadb_rx; saddr[3] = x->props.saddr.a4;
daddr[3] = x->id.daddr.a4;
} else {
memcpy(saddr, x->props.saddr.a6, sizeof(saddr));
memcpy(daddr, x->id.daddr.a6, sizeof(daddr));
is_ipv6 = true;
}
spi = x->id.spi;
sa_entry->hw_context =
mlx5_accel_esp_create_hw_context(priv->mdev,
sa_entry->xfrm,
saddr, daddr, spi,
is_ipv6);
if (IS_ERR(sa_entry->hw_context)) {
err = PTR_ERR(sa_entry->hw_context);
goto err_xfrm;
}
x->xso.offload_handle = (unsigned long)sa_entry; x->xso.offload_handle = (unsigned long)sa_entry;
goto out; goto out;
err_xfrm:
mlx5_accel_esp_destroy_xfrm(sa_entry->xfrm);
err_sadb_rx: err_sadb_rx:
if (x->xso.flags & XFRM_OFFLOAD_INBOUND) { if (x->xso.flags & XFRM_OFFLOAD_INBOUND) {
mlx5e_ipsec_sadb_rx_del(sa_entry); mlx5e_ipsec_sadb_rx_del(sa_entry);
...@@ -315,43 +368,26 @@ static int mlx5e_xfrm_add_state(struct xfrm_state *x) ...@@ -315,43 +368,26 @@ static int mlx5e_xfrm_add_state(struct xfrm_state *x)
static void mlx5e_xfrm_del_state(struct xfrm_state *x) static void mlx5e_xfrm_del_state(struct xfrm_state *x)
{ {
struct mlx5e_ipsec_sa_entry *sa_entry; struct mlx5e_ipsec_sa_entry *sa_entry = to_ipsec_sa_entry(x);
struct mlx5_accel_ipsec_sa hw_sa;
void *context;
if (!x->xso.offload_handle) if (!sa_entry)
return; return;
sa_entry = (struct mlx5e_ipsec_sa_entry *)x->xso.offload_handle;
WARN_ON(sa_entry->x != x);
if (x->xso.flags & XFRM_OFFLOAD_INBOUND) if (x->xso.flags & XFRM_OFFLOAD_INBOUND)
mlx5e_ipsec_sadb_rx_del(sa_entry); mlx5e_ipsec_sadb_rx_del(sa_entry);
mlx5e_ipsec_build_hw_sa(MLX5_IPSEC_CMD_DEL_SA, sa_entry, &hw_sa);
context = mlx5_accel_ipsec_sa_cmd_exec(sa_entry->ipsec->en_priv->mdev, &hw_sa);
if (IS_ERR(context))
return;
sa_entry->context = context;
} }
static void mlx5e_xfrm_free_state(struct xfrm_state *x) static void mlx5e_xfrm_free_state(struct xfrm_state *x)
{ {
struct mlx5e_ipsec_sa_entry *sa_entry; struct mlx5e_ipsec_sa_entry *sa_entry = to_ipsec_sa_entry(x);
int res;
if (!x->xso.offload_handle) if (!sa_entry)
return; return;
sa_entry = (struct mlx5e_ipsec_sa_entry *)x->xso.offload_handle; if (sa_entry->hw_context) {
WARN_ON(sa_entry->x != x); flush_workqueue(sa_entry->ipsec->wq);
mlx5_accel_esp_free_hw_context(sa_entry->hw_context);
res = mlx5_accel_ipsec_sa_cmd_wait(sa_entry->context); mlx5_accel_esp_destroy_xfrm(sa_entry->xfrm);
sa_entry->context = NULL;
if (res) {
/* Leftover object will leak */
return;
} }
if (x->xso.flags & XFRM_OFFLOAD_INBOUND) if (x->xso.flags & XFRM_OFFLOAD_INBOUND)
...@@ -378,6 +414,14 @@ int mlx5e_ipsec_init(struct mlx5e_priv *priv) ...@@ -378,6 +414,14 @@ int mlx5e_ipsec_init(struct mlx5e_priv *priv)
ida_init(&ipsec->halloc); ida_init(&ipsec->halloc);
ipsec->en_priv = priv; ipsec->en_priv = priv;
ipsec->en_priv->ipsec = ipsec; ipsec->en_priv->ipsec = ipsec;
ipsec->no_trailer = !!(mlx5_accel_ipsec_device_caps(priv->mdev) &
MLX5_ACCEL_IPSEC_CAP_RX_NO_TRAILER);
ipsec->wq = alloc_ordered_workqueue("mlx5e_ipsec: %s", 0,
priv->netdev->name);
if (!ipsec->wq) {
kfree(ipsec);
return -ENOMEM;
}
netdev_dbg(priv->netdev, "IPSec attached to netdevice\n"); netdev_dbg(priv->netdev, "IPSec attached to netdevice\n");
return 0; return 0;
} }
...@@ -389,6 +433,9 @@ void mlx5e_ipsec_cleanup(struct mlx5e_priv *priv) ...@@ -389,6 +433,9 @@ void mlx5e_ipsec_cleanup(struct mlx5e_priv *priv)
if (!ipsec) if (!ipsec)
return; return;
drain_workqueue(ipsec->wq);
destroy_workqueue(ipsec->wq);
ida_destroy(&ipsec->halloc); ida_destroy(&ipsec->halloc);
kfree(ipsec); kfree(ipsec);
priv->ipsec = NULL; priv->ipsec = NULL;
...@@ -409,11 +456,58 @@ static bool mlx5e_ipsec_offload_ok(struct sk_buff *skb, struct xfrm_state *x) ...@@ -409,11 +456,58 @@ static bool mlx5e_ipsec_offload_ok(struct sk_buff *skb, struct xfrm_state *x)
return true; return true;
} }
struct mlx5e_ipsec_modify_state_work {
struct work_struct work;
struct mlx5_accel_esp_xfrm_attrs attrs;
struct mlx5e_ipsec_sa_entry *sa_entry;
};
static void _update_xfrm_state(struct work_struct *work)
{
int ret;
struct mlx5e_ipsec_modify_state_work *modify_work =
container_of(work, struct mlx5e_ipsec_modify_state_work, work);
struct mlx5e_ipsec_sa_entry *sa_entry = modify_work->sa_entry;
ret = mlx5_accel_esp_modify_xfrm(sa_entry->xfrm,
&modify_work->attrs);
if (ret)
netdev_warn(sa_entry->ipsec->en_priv->netdev,
"Not an IPSec offload device\n");
kfree(modify_work);
}
static void mlx5e_xfrm_advance_esn_state(struct xfrm_state *x)
{
struct mlx5e_ipsec_sa_entry *sa_entry = to_ipsec_sa_entry(x);
struct mlx5e_ipsec_modify_state_work *modify_work;
bool need_update;
if (!sa_entry)
return;
need_update = mlx5e_ipsec_update_esn_state(sa_entry);
if (!need_update)
return;
modify_work = kzalloc(sizeof(*modify_work), GFP_ATOMIC);
if (!modify_work)
return;
mlx5e_ipsec_build_accel_xfrm_attrs(sa_entry, &modify_work->attrs);
modify_work->sa_entry = sa_entry;
INIT_WORK(&modify_work->work, _update_xfrm_state);
WARN_ON(!queue_work(sa_entry->ipsec->wq, &modify_work->work));
}
static const struct xfrmdev_ops mlx5e_ipsec_xfrmdev_ops = { static const struct xfrmdev_ops mlx5e_ipsec_xfrmdev_ops = {
.xdo_dev_state_add = mlx5e_xfrm_add_state, .xdo_dev_state_add = mlx5e_xfrm_add_state,
.xdo_dev_state_delete = mlx5e_xfrm_del_state, .xdo_dev_state_delete = mlx5e_xfrm_del_state,
.xdo_dev_state_free = mlx5e_xfrm_free_state, .xdo_dev_state_free = mlx5e_xfrm_free_state,
.xdo_dev_offload_ok = mlx5e_ipsec_offload_ok, .xdo_dev_offload_ok = mlx5e_ipsec_offload_ok,
.xdo_dev_state_advance_esn = mlx5e_xfrm_advance_esn_state,
}; };
void mlx5e_ipsec_build_netdev(struct mlx5e_priv *priv) void mlx5e_ipsec_build_netdev(struct mlx5e_priv *priv)
...@@ -424,7 +518,7 @@ void mlx5e_ipsec_build_netdev(struct mlx5e_priv *priv) ...@@ -424,7 +518,7 @@ void mlx5e_ipsec_build_netdev(struct mlx5e_priv *priv)
if (!priv->ipsec) if (!priv->ipsec)
return; return;
if (!(mlx5_accel_ipsec_device_caps(mdev) & MLX5_ACCEL_IPSEC_ESP) || if (!(mlx5_accel_ipsec_device_caps(mdev) & MLX5_ACCEL_IPSEC_CAP_ESP) ||
!MLX5_CAP_ETH(mdev, swp)) { !MLX5_CAP_ETH(mdev, swp)) {
mlx5_core_dbg(mdev, "mlx5e: ESP and SWP offload not supported\n"); mlx5_core_dbg(mdev, "mlx5e: ESP and SWP offload not supported\n");
return; return;
...@@ -443,7 +537,7 @@ void mlx5e_ipsec_build_netdev(struct mlx5e_priv *priv) ...@@ -443,7 +537,7 @@ void mlx5e_ipsec_build_netdev(struct mlx5e_priv *priv)
netdev->features |= NETIF_F_HW_ESP_TX_CSUM; netdev->features |= NETIF_F_HW_ESP_TX_CSUM;
netdev->hw_enc_features |= NETIF_F_HW_ESP_TX_CSUM; netdev->hw_enc_features |= NETIF_F_HW_ESP_TX_CSUM;
if (!(mlx5_accel_ipsec_device_caps(mdev) & MLX5_ACCEL_IPSEC_LSO) || if (!(mlx5_accel_ipsec_device_caps(mdev) & MLX5_ACCEL_IPSEC_CAP_LSO) ||
!MLX5_CAP_ETH(mdev, swp_lso)) { !MLX5_CAP_ETH(mdev, swp_lso)) {
mlx5_core_dbg(mdev, "mlx5e: ESP LSO not supported\n"); mlx5_core_dbg(mdev, "mlx5e: ESP LSO not supported\n");
return; return;
......
...@@ -40,7 +40,11 @@ ...@@ -40,7 +40,11 @@
#include <net/xfrm.h> #include <net/xfrm.h>
#include <linux/idr.h> #include <linux/idr.h>
#include "accel/ipsec.h"
#define MLX5E_IPSEC_SADB_RX_BITS 10 #define MLX5E_IPSEC_SADB_RX_BITS 10
#define MLX5E_IPSEC_ESN_SCOPE_MID 0x80000000L
#define MLX5E_METADATA_ETHER_TYPE (0x8CE4) #define MLX5E_METADATA_ETHER_TYPE (0x8CE4)
#define MLX5E_METADATA_ETHER_LEN 8 #define MLX5E_METADATA_ETHER_LEN 8
...@@ -77,10 +81,30 @@ struct mlx5e_ipsec_stats { ...@@ -77,10 +81,30 @@ struct mlx5e_ipsec_stats {
struct mlx5e_ipsec { struct mlx5e_ipsec {
struct mlx5e_priv *en_priv; struct mlx5e_priv *en_priv;
DECLARE_HASHTABLE(sadb_rx, MLX5E_IPSEC_SADB_RX_BITS); DECLARE_HASHTABLE(sadb_rx, MLX5E_IPSEC_SADB_RX_BITS);
bool no_trailer;
spinlock_t sadb_rx_lock; /* Protects sadb_rx and halloc */ spinlock_t sadb_rx_lock; /* Protects sadb_rx and halloc */
struct ida halloc; struct ida halloc;
struct mlx5e_ipsec_sw_stats sw_stats; struct mlx5e_ipsec_sw_stats sw_stats;
struct mlx5e_ipsec_stats stats; struct mlx5e_ipsec_stats stats;
struct workqueue_struct *wq;
};
struct mlx5e_ipsec_esn_state {
u32 esn;
u8 trigger: 1;
u8 overlap: 1;
};
struct mlx5e_ipsec_sa_entry {
struct hlist_node hlist; /* Item in SADB_RX hashtable */
struct mlx5e_ipsec_esn_state esn_state;
unsigned int handle; /* Handle in SADB_RX */
struct xfrm_state *x;
struct mlx5e_ipsec *ipsec;
struct mlx5_accel_esp_xfrm *xfrm;
void *hw_context;
void (*set_iv_op)(struct sk_buff *skb, struct xfrm_state *x,
struct xfrm_offload *xo);
}; };
void mlx5e_ipsec_build_inverse_table(void); void mlx5e_ipsec_build_inverse_table(void);
......
...@@ -42,10 +42,11 @@ ...@@ -42,10 +42,11 @@
enum { enum {
MLX5E_IPSEC_RX_SYNDROME_DECRYPTED = 0x11, MLX5E_IPSEC_RX_SYNDROME_DECRYPTED = 0x11,
MLX5E_IPSEC_RX_SYNDROME_AUTH_FAILED = 0x12, MLX5E_IPSEC_RX_SYNDROME_AUTH_FAILED = 0x12,
MLX5E_IPSEC_RX_SYNDROME_BAD_PROTO = 0x17,
}; };
struct mlx5e_ipsec_rx_metadata { struct mlx5e_ipsec_rx_metadata {
unsigned char reserved; unsigned char nexthdr;
__be32 sa_handle; __be32 sa_handle;
} __packed; } __packed;
...@@ -175,7 +176,30 @@ static void mlx5e_ipsec_set_swp(struct sk_buff *skb, ...@@ -175,7 +176,30 @@ static void mlx5e_ipsec_set_swp(struct sk_buff *skb,
} }
} }
static void mlx5e_ipsec_set_iv(struct sk_buff *skb, struct xfrm_offload *xo) void mlx5e_ipsec_set_iv_esn(struct sk_buff *skb, struct xfrm_state *x,
struct xfrm_offload *xo)
{
struct xfrm_replay_state_esn *replay_esn = x->replay_esn;
__u32 oseq = replay_esn->oseq;
int iv_offset;
__be64 seqno;
u32 seq_hi;
if (unlikely(skb_is_gso(skb) && oseq < MLX5E_IPSEC_ESN_SCOPE_MID &&
MLX5E_IPSEC_ESN_SCOPE_MID < (oseq - skb_shinfo(skb)->gso_segs))) {
seq_hi = xo->seq.hi - 1;
} else {
seq_hi = xo->seq.hi;
}
/* Place the SN in the IV field */
seqno = cpu_to_be64(xo->seq.low + ((u64)seq_hi << 32));
iv_offset = skb_transport_offset(skb) + sizeof(struct ip_esp_hdr);
skb_store_bits(skb, iv_offset, &seqno, 8);
}
void mlx5e_ipsec_set_iv(struct sk_buff *skb, struct xfrm_state *x,
struct xfrm_offload *xo)
{ {
int iv_offset; int iv_offset;
__be64 seqno; __be64 seqno;
...@@ -227,6 +251,7 @@ struct sk_buff *mlx5e_ipsec_handle_tx_skb(struct net_device *netdev, ...@@ -227,6 +251,7 @@ struct sk_buff *mlx5e_ipsec_handle_tx_skb(struct net_device *netdev,
struct mlx5e_priv *priv = netdev_priv(netdev); struct mlx5e_priv *priv = netdev_priv(netdev);
struct xfrm_offload *xo = xfrm_offload(skb); struct xfrm_offload *xo = xfrm_offload(skb);
struct mlx5e_ipsec_metadata *mdata; struct mlx5e_ipsec_metadata *mdata;
struct mlx5e_ipsec_sa_entry *sa_entry;
struct xfrm_state *x; struct xfrm_state *x;
if (!xo) if (!xo)
...@@ -261,7 +286,8 @@ struct sk_buff *mlx5e_ipsec_handle_tx_skb(struct net_device *netdev, ...@@ -261,7 +286,8 @@ struct sk_buff *mlx5e_ipsec_handle_tx_skb(struct net_device *netdev,
goto drop; goto drop;
} }
mlx5e_ipsec_set_swp(skb, &wqe->eth, x->props.mode, xo); mlx5e_ipsec_set_swp(skb, &wqe->eth, x->props.mode, xo);
mlx5e_ipsec_set_iv(skb, xo); sa_entry = (struct mlx5e_ipsec_sa_entry *)x->xso.offload_handle;
sa_entry->set_iv_op(skb, x, xo);
mlx5e_ipsec_set_metadata(skb, mdata, xo); mlx5e_ipsec_set_metadata(skb, mdata, xo);
return skb; return skb;
...@@ -301,10 +327,17 @@ mlx5e_ipsec_build_sp(struct net_device *netdev, struct sk_buff *skb, ...@@ -301,10 +327,17 @@ mlx5e_ipsec_build_sp(struct net_device *netdev, struct sk_buff *skb,
switch (mdata->syndrome) { switch (mdata->syndrome) {
case MLX5E_IPSEC_RX_SYNDROME_DECRYPTED: case MLX5E_IPSEC_RX_SYNDROME_DECRYPTED:
xo->status = CRYPTO_SUCCESS; xo->status = CRYPTO_SUCCESS;
if (likely(priv->ipsec->no_trailer)) {
xo->flags |= XFRM_ESP_NO_TRAILER;
xo->proto = mdata->content.rx.nexthdr;
}
break; break;
case MLX5E_IPSEC_RX_SYNDROME_AUTH_FAILED: case MLX5E_IPSEC_RX_SYNDROME_AUTH_FAILED:
xo->status = CRYPTO_TUNNEL_ESP_AUTH_FAILED; xo->status = CRYPTO_TUNNEL_ESP_AUTH_FAILED;
break; break;
case MLX5E_IPSEC_RX_SYNDROME_BAD_PROTO:
xo->status = CRYPTO_INVALID_PROTOCOL;
break;
default: default:
atomic64_inc(&priv->ipsec->sw_stats.ipsec_rx_drop_syndrome); atomic64_inc(&priv->ipsec->sw_stats.ipsec_rx_drop_syndrome);
return NULL; return NULL;
......
...@@ -37,6 +37,7 @@ ...@@ -37,6 +37,7 @@
#ifdef CONFIG_MLX5_EN_IPSEC #ifdef CONFIG_MLX5_EN_IPSEC
#include <linux/skbuff.h> #include <linux/skbuff.h>
#include <net/xfrm.h>
#include "en.h" #include "en.h"
struct sk_buff *mlx5e_ipsec_handle_rx_skb(struct net_device *netdev, struct sk_buff *mlx5e_ipsec_handle_rx_skb(struct net_device *netdev,
...@@ -46,6 +47,10 @@ void mlx5e_ipsec_handle_rx_cqe(struct mlx5e_rq *rq, struct mlx5_cqe64 *cqe); ...@@ -46,6 +47,10 @@ void mlx5e_ipsec_handle_rx_cqe(struct mlx5e_rq *rq, struct mlx5_cqe64 *cqe);
void mlx5e_ipsec_inverse_table_init(void); void mlx5e_ipsec_inverse_table_init(void);
bool mlx5e_ipsec_feature_check(struct sk_buff *skb, struct net_device *netdev, bool mlx5e_ipsec_feature_check(struct sk_buff *skb, struct net_device *netdev,
netdev_features_t features); netdev_features_t features);
void mlx5e_ipsec_set_iv_esn(struct sk_buff *skb, struct xfrm_state *x,
struct xfrm_offload *xo);
void mlx5e_ipsec_set_iv(struct sk_buff *skb, struct xfrm_state *x,
struct xfrm_offload *xo);
struct sk_buff *mlx5e_ipsec_handle_tx_skb(struct net_device *netdev, struct sk_buff *mlx5e_ipsec_handle_tx_skb(struct net_device *netdev,
struct mlx5e_tx_wqe *wqe, struct mlx5e_tx_wqe *wqe,
struct sk_buff *skb); struct sk_buff *skb);
......
...@@ -35,33 +35,38 @@ ...@@ -35,33 +35,38 @@
#define __MLX5_FPGA_IPSEC_H__ #define __MLX5_FPGA_IPSEC_H__
#include "accel/ipsec.h" #include "accel/ipsec.h"
#include "fs_cmd.h"
#ifdef CONFIG_MLX5_FPGA #ifdef CONFIG_MLX5_FPGA
void *mlx5_fpga_ipsec_sa_cmd_exec(struct mlx5_core_dev *mdev,
struct mlx5_accel_ipsec_sa *cmd);
int mlx5_fpga_ipsec_sa_cmd_wait(void *context);
u32 mlx5_fpga_ipsec_device_caps(struct mlx5_core_dev *mdev); u32 mlx5_fpga_ipsec_device_caps(struct mlx5_core_dev *mdev);
unsigned int mlx5_fpga_ipsec_counters_count(struct mlx5_core_dev *mdev); unsigned int mlx5_fpga_ipsec_counters_count(struct mlx5_core_dev *mdev);
int mlx5_fpga_ipsec_counters_read(struct mlx5_core_dev *mdev, u64 *counters, int mlx5_fpga_ipsec_counters_read(struct mlx5_core_dev *mdev, u64 *counters,
unsigned int counters_count); unsigned int counters_count);
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);
void mlx5_fpga_ipsec_delete_sa_ctx(void *context);
int mlx5_fpga_ipsec_init(struct mlx5_core_dev *mdev); int mlx5_fpga_ipsec_init(struct mlx5_core_dev *mdev);
void mlx5_fpga_ipsec_cleanup(struct mlx5_core_dev *mdev); void mlx5_fpga_ipsec_cleanup(struct mlx5_core_dev *mdev);
void mlx5_fpga_ipsec_build_fs_cmds(void);
#else struct mlx5_accel_esp_xfrm *
mlx5_fpga_esp_create_xfrm(struct mlx5_core_dev *mdev,
const struct mlx5_accel_esp_xfrm_attrs *attrs,
u32 flags);
void mlx5_fpga_esp_destroy_xfrm(struct mlx5_accel_esp_xfrm *xfrm);
int mlx5_fpga_esp_modify_xfrm(struct mlx5_accel_esp_xfrm *xfrm,
const struct mlx5_accel_esp_xfrm_attrs *attrs);
static inline void *mlx5_fpga_ipsec_sa_cmd_exec(struct mlx5_core_dev *mdev, const struct mlx5_flow_cmds *
struct mlx5_accel_ipsec_sa *cmd) mlx5_fs_cmd_get_default_ipsec_fpga_cmds(enum fs_flow_table_type type);
{
return ERR_PTR(-EOPNOTSUPP);
}
static inline int mlx5_fpga_ipsec_sa_cmd_wait(void *context) #else
{
return -EOPNOTSUPP;
}
static inline u32 mlx5_fpga_ipsec_device_caps(struct mlx5_core_dev *mdev) static inline u32 mlx5_fpga_ipsec_device_caps(struct mlx5_core_dev *mdev)
{ {
...@@ -80,6 +85,20 @@ static inline int mlx5_fpga_ipsec_counters_read(struct mlx5_core_dev *mdev, ...@@ -80,6 +85,20 @@ static inline int mlx5_fpga_ipsec_counters_read(struct mlx5_core_dev *mdev,
return 0; return 0;
} }
static inline 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)
{
return NULL;
}
static inline void mlx5_fpga_ipsec_delete_sa_ctx(void *context)
{
}
static inline int mlx5_fpga_ipsec_init(struct mlx5_core_dev *mdev) static inline int mlx5_fpga_ipsec_init(struct mlx5_core_dev *mdev)
{ {
return 0; return 0;
...@@ -89,6 +108,35 @@ static inline void mlx5_fpga_ipsec_cleanup(struct mlx5_core_dev *mdev) ...@@ -89,6 +108,35 @@ static inline void mlx5_fpga_ipsec_cleanup(struct mlx5_core_dev *mdev)
{ {
} }
static inline void mlx5_fpga_ipsec_build_fs_cmds(void)
{
}
static inline struct mlx5_accel_esp_xfrm *
mlx5_fpga_esp_create_xfrm(struct mlx5_core_dev *mdev,
const struct mlx5_accel_esp_xfrm_attrs *attrs,
u32 flags)
{
return ERR_PTR(-EOPNOTSUPP);
}
static inline void mlx5_fpga_esp_destroy_xfrm(struct mlx5_accel_esp_xfrm *xfrm)
{
}
static inline int
mlx5_fpga_esp_modify_xfrm(struct mlx5_accel_esp_xfrm *xfrm,
const struct mlx5_accel_esp_xfrm_attrs *attrs)
{
return -EOPNOTSUPP;
}
static inline const struct mlx5_flow_cmds *
mlx5_fs_cmd_get_default_ipsec_fpga_cmds(enum fs_flow_table_type type)
{
return mlx5_fs_cmd_get_default(type);
}
#endif /* CONFIG_MLX5_FPGA */ #endif /* CONFIG_MLX5_FPGA */
#endif /* __MLX5_FPGA_SADB_H__ */ #endif /* __MLX5_FPGA_SADB_H__ */
...@@ -38,6 +38,7 @@ ...@@ -38,6 +38,7 @@
#include "fs_cmd.h" #include "fs_cmd.h"
#include "diag/fs_tracepoint.h" #include "diag/fs_tracepoint.h"
#include "accel/ipsec.h" #include "accel/ipsec.h"
#include "fpga/ipsec.h"
#define INIT_TREE_NODE_ARRAY_SIZE(...) (sizeof((struct init_tree_node[]){__VA_ARGS__}) /\ #define INIT_TREE_NODE_ARRAY_SIZE(...) (sizeof((struct init_tree_node[]){__VA_ARGS__}) /\
sizeof(struct init_tree_node)) sizeof(struct init_tree_node))
...@@ -2258,6 +2259,10 @@ static struct mlx5_flow_root_namespace ...@@ -2258,6 +2259,10 @@ static struct mlx5_flow_root_namespace
struct mlx5_flow_root_namespace *root_ns; struct mlx5_flow_root_namespace *root_ns;
struct mlx5_flow_namespace *ns; struct mlx5_flow_namespace *ns;
if (mlx5_accel_ipsec_device_caps(steering->dev) & MLX5_ACCEL_IPSEC_CAP_DEVICE &&
(table_type == FS_FT_NIC_RX || table_type == FS_FT_NIC_TX))
cmds = mlx5_fs_cmd_get_default_ipsec_fpga_cmds(table_type);
/* Create the root namespace */ /* Create the root namespace */
root_ns = kvzalloc(sizeof(*root_ns), GFP_KERNEL); root_ns = kvzalloc(sizeof(*root_ns), GFP_KERNEL);
if (!root_ns) if (!root_ns)
...@@ -2649,8 +2654,7 @@ int mlx5_init_fs(struct mlx5_core_dev *dev) ...@@ -2649,8 +2654,7 @@ int mlx5_init_fs(struct mlx5_core_dev *dev)
goto err; goto err;
} }
if (mlx5_accel_ipsec_device_caps(steering->dev) & if (MLX5_IPSEC_DEV(dev)) {
MLX5_ACCEL_IPSEC_DEVICE) {
err = init_egress_root_ns(steering); err = init_egress_root_ns(steering);
if (err) if (err)
goto err; goto err;
......
...@@ -58,6 +58,7 @@ ...@@ -58,6 +58,7 @@
#include "eswitch.h" #include "eswitch.h"
#include "lib/mlx5.h" #include "lib/mlx5.h"
#include "fpga/core.h" #include "fpga/core.h"
#include "fpga/ipsec.h"
#include "accel/ipsec.h" #include "accel/ipsec.h"
#include "lib/clock.h" #include "lib/clock.h"
...@@ -1658,6 +1659,7 @@ static int __init init(void) ...@@ -1658,6 +1659,7 @@ static int __init init(void)
get_random_bytes(&sw_owner_id, sizeof(sw_owner_id)); get_random_bytes(&sw_owner_id, sizeof(sw_owner_id));
mlx5_core_verify_params(); mlx5_core_verify_params();
mlx5_fpga_ipsec_build_fs_cmds();
mlx5_register_debugfs(); mlx5_register_debugfs();
err = pci_register_driver(&mlx5_core_driver); err = pci_register_driver(&mlx5_core_driver);
......
/*
* Copyright (c) 2018 Mellanox Technologies. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
* General Public License (GPL) Version 2, available from the file
* COPYING in the main directory of this source tree, or the
* OpenIB.org BSD license below:
*
* 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.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*/
#ifndef __MLX5_ACCEL_H__
#define __MLX5_ACCEL_H__
#include <linux/mlx5/driver.h>
enum mlx5_accel_esp_aes_gcm_keymat_iv_algo {
MLX5_ACCEL_ESP_AES_GCM_IV_ALGO_SEQ,
};
enum mlx5_accel_esp_flags {
MLX5_ACCEL_ESP_FLAGS_TUNNEL = 0, /* Default */
MLX5_ACCEL_ESP_FLAGS_TRANSPORT = 1UL << 0,
MLX5_ACCEL_ESP_FLAGS_ESN_TRIGGERED = 1UL << 1,
MLX5_ACCEL_ESP_FLAGS_ESN_STATE_OVERLAP = 1UL << 2,
};
enum mlx5_accel_esp_action {
MLX5_ACCEL_ESP_ACTION_DECRYPT,
MLX5_ACCEL_ESP_ACTION_ENCRYPT,
};
enum mlx5_accel_esp_keymats {
MLX5_ACCEL_ESP_KEYMAT_AES_NONE,
MLX5_ACCEL_ESP_KEYMAT_AES_GCM,
};
enum mlx5_accel_esp_replay {
MLX5_ACCEL_ESP_REPLAY_NONE,
MLX5_ACCEL_ESP_REPLAY_BMP,
};
struct aes_gcm_keymat {
u64 seq_iv;
enum mlx5_accel_esp_aes_gcm_keymat_iv_algo iv_algo;
u32 salt;
u32 icv_len;
u32 key_len;
u32 aes_key[256 / 32];
};
struct mlx5_accel_esp_xfrm_attrs {
enum mlx5_accel_esp_action action;
u32 esn;
u32 spi;
u32 seq;
u32 tfc_pad;
u32 flags;
u32 sa_handle;
enum mlx5_accel_esp_replay replay_type;
union {
struct {
u32 size;
} bmp;
} replay;
enum mlx5_accel_esp_keymats keymat_type;
union {
struct aes_gcm_keymat aes_gcm;
} keymat;
};
struct mlx5_accel_esp_xfrm {
struct mlx5_core_dev *mdev;
struct mlx5_accel_esp_xfrm_attrs attrs;
};
enum {
MLX5_ACCEL_XFRM_FLAG_REQUIRE_METADATA = 1UL << 0,
};
enum mlx5_accel_ipsec_cap {
MLX5_ACCEL_IPSEC_CAP_DEVICE = 1 << 0,
MLX5_ACCEL_IPSEC_CAP_REQUIRED_METADATA = 1 << 1,
MLX5_ACCEL_IPSEC_CAP_ESP = 1 << 2,
MLX5_ACCEL_IPSEC_CAP_IPV6 = 1 << 3,
MLX5_ACCEL_IPSEC_CAP_LSO = 1 << 4,
MLX5_ACCEL_IPSEC_CAP_RX_NO_TRAILER = 1 << 5,
MLX5_ACCEL_IPSEC_CAP_ESN = 1 << 6,
MLX5_ACCEL_IPSEC_CAP_TX_IV_IS_ESN = 1 << 7,
};
#ifdef CONFIG_MLX5_ACCEL
u32 mlx5_accel_ipsec_device_caps(struct mlx5_core_dev *mdev);
struct mlx5_accel_esp_xfrm *
mlx5_accel_esp_create_xfrm(struct mlx5_core_dev *mdev,
const struct mlx5_accel_esp_xfrm_attrs *attrs,
u32 flags);
void mlx5_accel_esp_destroy_xfrm(struct mlx5_accel_esp_xfrm *xfrm);
int mlx5_accel_esp_modify_xfrm(struct mlx5_accel_esp_xfrm *xfrm,
const struct mlx5_accel_esp_xfrm_attrs *attrs);
#else
static inline u32 mlx5_accel_ipsec_device_caps(struct mlx5_core_dev *mdev) { return 0; }
static inline struct mlx5_accel_esp_xfrm *
mlx5_accel_esp_create_xfrm(struct mlx5_core_dev *mdev,
const struct mlx5_accel_esp_xfrm_attrs *attrs,
u32 flags) { return ERR_PTR(-EOPNOTSUPP); }
static inline void
mlx5_accel_esp_destroy_xfrm(struct mlx5_accel_esp_xfrm *xfrm) {}
static inline int
mlx5_accel_esp_modify_xfrm(struct mlx5_accel_esp_xfrm *xfrm,
const struct mlx5_accel_esp_xfrm_attrs *attrs) { return -EOPNOTSUPP; }
#endif
#endif
...@@ -40,6 +40,8 @@ ...@@ -40,6 +40,8 @@
enum { enum {
MLX5_FLOW_CONTEXT_ACTION_FWD_NEXT_PRIO = 1 << 16, MLX5_FLOW_CONTEXT_ACTION_FWD_NEXT_PRIO = 1 << 16,
MLX5_FLOW_CONTEXT_ACTION_ENCRYPT = 1 << 17,
MLX5_FLOW_CONTEXT_ACTION_DECRYPT = 1 << 18,
}; };
enum { enum {
...@@ -146,6 +148,7 @@ struct mlx5_flow_act { ...@@ -146,6 +148,7 @@ struct mlx5_flow_act {
u32 flow_tag; u32 flow_tag;
u32 encap_id; u32 encap_id;
u32 modify_id; u32 modify_id;
uintptr_t esp_id;
}; };
#define MLX5_DECLARE_FLOW_ACT(name) \ #define MLX5_DECLARE_FLOW_ACT(name) \
......
...@@ -373,7 +373,10 @@ struct mlx5_ifc_fpga_destroy_qp_out_bits { ...@@ -373,7 +373,10 @@ struct mlx5_ifc_fpga_destroy_qp_out_bits {
struct mlx5_ifc_ipsec_extended_cap_bits { struct mlx5_ifc_ipsec_extended_cap_bits {
u8 encapsulation[0x20]; u8 encapsulation[0x20];
u8 reserved_0[0x15]; u8 reserved_0[0x12];
u8 v2_command[0x1];
u8 udp_encap[0x1];
u8 rx_no_trailer[0x1];
u8 ipv4_fragment[0x1]; u8 ipv4_fragment[0x1];
u8 ipv6[0x1]; u8 ipv6[0x1];
u8 esn[0x1]; u8 esn[0x1];
...@@ -429,4 +432,91 @@ struct mlx5_ifc_ipsec_counters_bits { ...@@ -429,4 +432,91 @@ struct mlx5_ifc_ipsec_counters_bits {
u8 dropped_cmd[0x40]; u8 dropped_cmd[0x40];
}; };
enum mlx5_ifc_fpga_ipsec_response_syndrome {
MLX5_FPGA_IPSEC_RESPONSE_SUCCESS = 0,
MLX5_FPGA_IPSEC_RESPONSE_ILLEGAL_REQUEST = 1,
MLX5_FPGA_IPSEC_RESPONSE_SADB_ISSUE = 2,
MLX5_FPGA_IPSEC_RESPONSE_WRITE_RESPONSE_ISSUE = 3,
};
struct mlx5_ifc_fpga_ipsec_cmd_resp {
__be32 syndrome;
union {
__be32 sw_sa_handle;
__be32 flags;
};
u8 reserved[24];
} __packed;
enum mlx5_ifc_fpga_ipsec_cmd_opcode {
MLX5_FPGA_IPSEC_CMD_OP_ADD_SA = 0,
MLX5_FPGA_IPSEC_CMD_OP_DEL_SA = 1,
MLX5_FPGA_IPSEC_CMD_OP_ADD_SA_V2 = 2,
MLX5_FPGA_IPSEC_CMD_OP_DEL_SA_V2 = 3,
MLX5_FPGA_IPSEC_CMD_OP_MOD_SA_V2 = 4,
MLX5_FPGA_IPSEC_CMD_OP_SET_CAP = 5,
};
enum mlx5_ifc_fpga_ipsec_cap {
MLX5_FPGA_IPSEC_CAP_NO_TRAILER = BIT(0),
};
struct mlx5_ifc_fpga_ipsec_cmd_cap {
__be32 cmd;
__be32 flags;
u8 reserved[24];
} __packed;
enum mlx5_ifc_fpga_ipsec_sa_flags {
MLX5_FPGA_IPSEC_SA_ESN_EN = BIT(0),
MLX5_FPGA_IPSEC_SA_ESN_OVERLAP = BIT(1),
MLX5_FPGA_IPSEC_SA_IPV6 = BIT(2),
MLX5_FPGA_IPSEC_SA_DIR_SX = BIT(3),
MLX5_FPGA_IPSEC_SA_SPI_EN = BIT(4),
MLX5_FPGA_IPSEC_SA_SA_VALID = BIT(5),
MLX5_FPGA_IPSEC_SA_IP_ESP = BIT(6),
MLX5_FPGA_IPSEC_SA_IP_AH = BIT(7),
};
enum mlx5_ifc_fpga_ipsec_sa_enc_mode {
MLX5_FPGA_IPSEC_SA_ENC_MODE_NONE = 0,
MLX5_FPGA_IPSEC_SA_ENC_MODE_AES_GCM_128_AUTH_128 = 1,
MLX5_FPGA_IPSEC_SA_ENC_MODE_AES_GCM_256_AUTH_128 = 3,
};
struct mlx5_ifc_fpga_ipsec_sa_v1 {
__be32 cmd;
u8 key_enc[32];
u8 key_auth[32];
__be32 sip[4];
__be32 dip[4];
union {
struct {
__be32 reserved;
u8 salt_iv[8];
__be32 salt;
} __packed gcm;
struct {
u8 salt[16];
} __packed cbc;
};
__be32 spi;
__be32 sw_sa_handle;
__be16 tfclen;
u8 enc_mode;
u8 reserved1[2];
u8 flags;
u8 reserved2[2];
};
struct mlx5_ifc_fpga_ipsec_sa {
struct mlx5_ifc_fpga_ipsec_sa_v1 ipsec_sa_v1;
__be16 udp_sp;
__be16 udp_dp;
u8 reserved1[4];
__be32 esn;
__be16 vid; /* only 12 bits, rest is reserved */
__be16 reserved2;
} __packed;
#endif /* MLX5_IFC_FPGA_H */ #endif /* MLX5_IFC_FPGA_H */
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册