cryptodev: make xform key pointer constant
[dpdk.git] / drivers / net / ixgbe / ixgbe_ipsec.c
index 97f025a..48f5082 100644 (file)
@@ -2,7 +2,7 @@
  * Copyright(c) 2010-2017 Intel Corporation
  */
 
-#include <rte_ethdev.h>
+#include <rte_ethdev_driver.h>
 #include <rte_ethdev_pci.h>
 #include <rte_ip.h>
 #include <rte_jhash.h>
@@ -41,6 +41,8 @@ static void
 ixgbe_crypto_clear_ipsec_tables(struct rte_eth_dev *dev)
 {
        struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+       struct ixgbe_ipsec *priv = IXGBE_DEV_PRIVATE_TO_IPSEC(
+                               dev->data->dev_private);
        int i = 0;
 
        /* clear Rx IP table*/
@@ -77,6 +79,10 @@ ixgbe_crypto_clear_ipsec_tables(struct rte_eth_dev *dev)
                IXGBE_WRITE_REG(hw, IXGBE_IPSTXSALT, 0);
                IXGBE_WAIT_TWRITE;
        }
+
+       memset(priv->rx_ip_tbl, 0, sizeof(priv->rx_ip_tbl));
+       memset(priv->rx_sa_tbl, 0, sizeof(priv->rx_sa_tbl));
+       memset(priv->tx_sa_tbl, 0, sizeof(priv->tx_sa_tbl));
 }
 
 static int
@@ -91,6 +97,7 @@ ixgbe_crypto_add_sa(struct ixgbe_crypto_session *ic_session)
 
        if (ic_session->op == IXGBE_OP_AUTHENTICATED_DECRYPTION) {
                int i, ip_index = -1;
+               uint8_t *key;
 
                /* Find a match in the IP table*/
                for (i = 0; i < IPSEC_MAX_RX_IP_COUNT; i++) {
@@ -144,22 +151,16 @@ ixgbe_crypto_add_sa(struct ixgbe_crypto_session *ic_session)
                priv->rx_sa_tbl[sa_index].spi =
                        rte_cpu_to_be_32(ic_session->spi);
                priv->rx_sa_tbl[sa_index].ip_index = ip_index;
-               priv->rx_sa_tbl[sa_index].key[3] =
-                       rte_cpu_to_be_32(*(uint32_t *)&ic_session->key[0]);
-               priv->rx_sa_tbl[sa_index].key[2] =
-                       rte_cpu_to_be_32(*(uint32_t *)&ic_session->key[4]);
-               priv->rx_sa_tbl[sa_index].key[1] =
-                       rte_cpu_to_be_32(*(uint32_t *)&ic_session->key[8]);
-               priv->rx_sa_tbl[sa_index].key[0] =
-                       rte_cpu_to_be_32(*(uint32_t *)&ic_session->key[12]);
-               priv->rx_sa_tbl[sa_index].salt =
-                       rte_cpu_to_be_32(ic_session->salt);
                priv->rx_sa_tbl[sa_index].mode = IPSRXMOD_VALID;
                if (ic_session->op == IXGBE_OP_AUTHENTICATED_DECRYPTION)
                        priv->rx_sa_tbl[sa_index].mode |=
                                        (IPSRXMOD_PROTO | IPSRXMOD_DECRYPT);
-               if (ic_session->dst_ip.type == IPv6)
+               if (ic_session->dst_ip.type == IPv6) {
                        priv->rx_sa_tbl[sa_index].mode |= IPSRXMOD_IPV6;
+                       priv->rx_ip_tbl[ip_index].ip.type = IPv6;
+               } else if (ic_session->dst_ip.type == IPv4)
+                       priv->rx_ip_tbl[ip_index].ip.type = IPv4;
+
                priv->rx_sa_tbl[sa_index].used = 1;
 
                /* write IP table entry*/
@@ -193,23 +194,32 @@ ixgbe_crypto_add_sa(struct ixgbe_crypto_session *ic_session)
                IXGBE_WAIT_RWRITE;
 
                /* write Key table entry*/
+               key = malloc(ic_session->key_len);
+               if (!key)
+                       return -ENOMEM;
+
+               memcpy(key, ic_session->key, ic_session->key_len);
+
                reg_val = IPSRXIDX_RX_EN | IPSRXIDX_WRITE |
                                IPSRXIDX_TABLE_KEY | (sa_index << 3);
                IXGBE_WRITE_REG(hw, IXGBE_IPSRXKEY(0),
-                               priv->rx_sa_tbl[sa_index].key[0]);
+                       rte_cpu_to_be_32(*(uint32_t *)&key[12]));
                IXGBE_WRITE_REG(hw, IXGBE_IPSRXKEY(1),
-                               priv->rx_sa_tbl[sa_index].key[1]);
+                       rte_cpu_to_be_32(*(uint32_t *)&key[8]));
                IXGBE_WRITE_REG(hw, IXGBE_IPSRXKEY(2),
-                               priv->rx_sa_tbl[sa_index].key[2]);
+                       rte_cpu_to_be_32(*(uint32_t *)&key[4]));
                IXGBE_WRITE_REG(hw, IXGBE_IPSRXKEY(3),
-                               priv->rx_sa_tbl[sa_index].key[3]);
+                       rte_cpu_to_be_32(*(uint32_t *)&key[0]));
                IXGBE_WRITE_REG(hw, IXGBE_IPSRXSALT,
-                               priv->rx_sa_tbl[sa_index].salt);
+                               rte_cpu_to_be_32(ic_session->salt));
                IXGBE_WRITE_REG(hw, IXGBE_IPSRXMOD,
                                priv->rx_sa_tbl[sa_index].mode);
                IXGBE_WAIT_RWRITE;
 
+               free(key);
+
        } else { /* sess->dir == RTE_CRYPTO_OUTBOUND */
+               uint8_t *key;
                int i;
 
                /* Find a free entry in the SA table*/
@@ -228,32 +238,30 @@ ixgbe_crypto_add_sa(struct ixgbe_crypto_session *ic_session)
 
                priv->tx_sa_tbl[sa_index].spi =
                        rte_cpu_to_be_32(ic_session->spi);
-               priv->tx_sa_tbl[sa_index].key[3] =
-                       rte_cpu_to_be_32(*(uint32_t *)&ic_session->key[0]);
-               priv->tx_sa_tbl[sa_index].key[2] =
-                       rte_cpu_to_be_32(*(uint32_t *)&ic_session->key[4]);
-               priv->tx_sa_tbl[sa_index].key[1] =
-                       rte_cpu_to_be_32(*(uint32_t *)&ic_session->key[8]);
-               priv->tx_sa_tbl[sa_index].key[0] =
-                       rte_cpu_to_be_32(*(uint32_t *)&ic_session->key[12]);
-               priv->tx_sa_tbl[sa_index].salt =
-                       rte_cpu_to_be_32(ic_session->salt);
+               priv->tx_sa_tbl[i].used = 1;
+               ic_session->sa_index = sa_index;
+
+               key = malloc(ic_session->key_len);
+               if (!key)
+                       return -ENOMEM;
+
+               memcpy(key, ic_session->key, ic_session->key_len);
 
+               /* write Key table entry*/
                reg_val = IPSRXIDX_RX_EN | IPSRXIDX_WRITE | (sa_index << 3);
                IXGBE_WRITE_REG(hw, IXGBE_IPSTXKEY(0),
-                               priv->tx_sa_tbl[sa_index].key[0]);
+                       rte_cpu_to_be_32(*(uint32_t *)&key[12]));
                IXGBE_WRITE_REG(hw, IXGBE_IPSTXKEY(1),
-                               priv->tx_sa_tbl[sa_index].key[1]);
+                       rte_cpu_to_be_32(*(uint32_t *)&key[8]));
                IXGBE_WRITE_REG(hw, IXGBE_IPSTXKEY(2),
-                               priv->tx_sa_tbl[sa_index].key[2]);
+                       rte_cpu_to_be_32(*(uint32_t *)&key[4]));
                IXGBE_WRITE_REG(hw, IXGBE_IPSTXKEY(3),
-                               priv->tx_sa_tbl[sa_index].key[3]);
+                       rte_cpu_to_be_32(*(uint32_t *)&key[0]));
                IXGBE_WRITE_REG(hw, IXGBE_IPSTXSALT,
-                               priv->tx_sa_tbl[sa_index].salt);
+                               rte_cpu_to_be_32(ic_session->salt));
                IXGBE_WAIT_TWRITE;
 
-               priv->tx_sa_tbl[i].used = 1;
-               ic_session->sa_index = sa_index;
+               free(key);
        }
 
        return 0;
@@ -378,6 +386,7 @@ ixgbe_crypto_create_session(void *device,
                        conf->crypto_xform->aead.algo !=
                                        RTE_CRYPTO_AEAD_AES_GCM) {
                PMD_DRV_LOG(ERR, "Unsupported crypto transformation mode\n");
+               rte_mempool_put(mempool, (void *)ic_session);
                return -ENOTSUP;
        }
        aead_xform = &conf->crypto_xform->aead;
@@ -387,6 +396,7 @@ ixgbe_crypto_create_session(void *device,
                        ic_session->op = IXGBE_OP_AUTHENTICATED_DECRYPTION;
                } else {
                        PMD_DRV_LOG(ERR, "IPsec decryption not enabled\n");
+                       rte_mempool_put(mempool, (void *)ic_session);
                        return -ENOTSUP;
                }
        } else {
@@ -394,11 +404,13 @@ ixgbe_crypto_create_session(void *device,
                        ic_session->op = IXGBE_OP_AUTHENTICATED_ENCRYPTION;
                } else {
                        PMD_DRV_LOG(ERR, "IPsec encryption not enabled\n");
+                       rte_mempool_put(mempool, (void *)ic_session);
                        return -ENOTSUP;
                }
        }
 
        ic_session->key = aead_xform->key.data;
+       ic_session->key_len = aead_xform->key.length;
        memcpy(&ic_session->salt,
               &aead_xform->key.data[aead_xform->key.length], 4);
        ic_session->spi = conf->ipsec.spi;
@@ -409,6 +421,7 @@ ixgbe_crypto_create_session(void *device,
        if (ic_session->op == IXGBE_OP_AUTHENTICATED_ENCRYPTION) {
                if (ixgbe_crypto_add_sa(ic_session)) {
                        PMD_DRV_LOG(ERR, "Failed to add SA\n");
+                       rte_mempool_put(mempool, (void *)ic_session);
                        return -EPERM;
                }
        }
@@ -416,6 +429,12 @@ ixgbe_crypto_create_session(void *device,
        return 0;
 }
 
+static unsigned int
+ixgbe_crypto_session_get_size(__rte_unused void *device)
+{
+       return sizeof(struct ixgbe_crypto_session);
+}
+
 static int
 ixgbe_crypto_remove_session(void *device,
                struct rte_security_session *session)
@@ -606,13 +625,18 @@ ixgbe_crypto_enable_ipsec(struct rte_eth_dev *dev)
 {
        struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
        uint32_t reg;
+       uint64_t rx_offloads;
+       uint64_t tx_offloads;
+
+       rx_offloads = dev->data->dev_conf.rxmode.offloads;
+       tx_offloads = dev->data->dev_conf.txmode.offloads;
 
        /* sanity checks */
-       if (dev->data->dev_conf.rxmode.enable_lro) {
+       if (rx_offloads & DEV_RX_OFFLOAD_TCP_LRO) {
                PMD_DRV_LOG(ERR, "RSC and IPsec not supported");
                return -1;
        }
-       if (!dev->data->dev_conf.rxmode.hw_strip_crc) {
+       if (rx_offloads & DEV_RX_OFFLOAD_KEEP_CRC) {
                PMD_DRV_LOG(ERR, "HW CRC strip needs to be enabled for IPsec");
                return -1;
        }
@@ -632,7 +656,7 @@ ixgbe_crypto_enable_ipsec(struct rte_eth_dev *dev)
        reg |= IXGBE_HLREG0_TXCRCEN | IXGBE_HLREG0_RXCRCSTRP;
        IXGBE_WRITE_REG(hw, IXGBE_HLREG0, reg);
 
-       if (dev->data->dev_conf.rxmode.offloads & DEV_RX_OFFLOAD_SECURITY) {
+       if (rx_offloads & DEV_RX_OFFLOAD_SECURITY) {
                IXGBE_WRITE_REG(hw, IXGBE_SECRXCTRL, 0);
                reg = IXGBE_READ_REG(hw, IXGBE_SECRXCTRL);
                if (reg != 0) {
@@ -640,7 +664,7 @@ ixgbe_crypto_enable_ipsec(struct rte_eth_dev *dev)
                        return -1;
                }
        }
-       if (dev->data->dev_conf.txmode.offloads & DEV_TX_OFFLOAD_SECURITY) {
+       if (tx_offloads & DEV_TX_OFFLOAD_SECURITY) {
                IXGBE_WRITE_REG(hw, IXGBE_SECTXCTRL,
                                IXGBE_SECTXCTRL_STORE_FORWARD);
                reg = IXGBE_READ_REG(hw, IXGBE_SECTXCTRL);
@@ -688,21 +712,44 @@ ixgbe_crypto_add_ingress_sa_from_flow(const void *sess,
 static struct rte_security_ops ixgbe_security_ops = {
        .session_create = ixgbe_crypto_create_session,
        .session_update = NULL,
+       .session_get_size = ixgbe_crypto_session_get_size,
        .session_stats_get = NULL,
        .session_destroy = ixgbe_crypto_remove_session,
        .set_pkt_metadata = ixgbe_crypto_update_mb,
        .capabilities_get = ixgbe_crypto_capabilities_get
 };
 
-struct rte_security_ctx *
+static int
+ixgbe_crypto_capable(struct rte_eth_dev *dev)
+{
+       struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+       uint32_t reg_i, reg, capable = 1;
+       /* test if rx crypto can be enabled and then write back initial value*/
+       reg_i = IXGBE_READ_REG(hw, IXGBE_SECRXCTRL);
+       IXGBE_WRITE_REG(hw, IXGBE_SECRXCTRL, 0);
+       reg = IXGBE_READ_REG(hw, IXGBE_SECRXCTRL);
+       if (reg != 0)
+               capable = 0;
+       IXGBE_WRITE_REG(hw, IXGBE_SECRXCTRL, reg_i);
+       return capable;
+}
+
+int
 ixgbe_ipsec_ctx_create(struct rte_eth_dev *dev)
 {
-       struct rte_security_ctx *ctx = rte_malloc("rte_security_instances_ops",
-                                       sizeof(struct rte_security_ctx), 0);
-       if (ctx) {
-               ctx->device = (void *)dev;
-               ctx->ops = &ixgbe_security_ops;
-               ctx->sess_cnt = 0;
+       struct rte_security_ctx *ctx = NULL;
+
+       if (ixgbe_crypto_capable(dev)) {
+               ctx = rte_malloc("rte_security_instances_ops",
+                                sizeof(struct rte_security_ctx), 0);
+               if (ctx) {
+                       ctx->device = (void *)dev;
+                       ctx->ops = &ixgbe_security_ops;
+                       ctx->sess_cnt = 0;
+                       dev->security_ctx = ctx;
+               } else {
+                       return -ENOMEM;
+               }
        }
-       return ctx;
+       return 0;
 }