From: Aviad Yehezkel <avia...@mellanox.com>

This feature is only supported by ConnectX-4 Lx INNOVA NIC.  Having such
support will automatically disable and enable crypto offload device
arguments to make the PMD IPsec capable.

Signed-off-by: Aviad Yehezkel <avia...@mellanox.com>
Signed-off-by: Nelio Laranjeiro <nelio.laranje...@6wind.com>
---
 drivers/net/mlx5/mlx5.c        |   8 ++++
 drivers/net/mlx5/mlx5.h        |   1 +
 drivers/net/mlx5/mlx5_ethdev.c |   4 ++
 drivers/net/mlx5/mlx5_prm.h    |  39 ++++++++++++++++
 drivers/net/mlx5/mlx5_rxtx.c   | 104 ++++++++++++++++++++++++++++++++++++++---
 drivers/net/mlx5/mlx5_rxtx.h   |   4 +-
 drivers/net/mlx5/mlx5_txq.c    |   1 +
 7 files changed, 154 insertions(+), 7 deletions(-)

diff --git a/drivers/net/mlx5/mlx5.c b/drivers/net/mlx5/mlx5.c
index cd66fe162..00480cef0 100644
--- a/drivers/net/mlx5/mlx5.c
+++ b/drivers/net/mlx5/mlx5.c
@@ -106,6 +106,14 @@
 #define MLX5DV_CONTEXT_FLAGS_CQE_128B_COMP (1 << 4)
 #endif
 
+#ifdef HAVE_IBV_IPSEC_SUPPORT
+#define MLX5_IPSEC_FLAGS \
+       (MLX5DV_CONTEXT_XFRM_FLAGS_ESP_AES_GCM_TX | \
+        MLX5DV_CONTEXT_XFRM_FLAGS_ESP_AES_GCM_RX | \
+        MLX5DV_CONTEXT_XFRM_FLAGS_ESP_AES_GCM_REQ_METADATA | \
+        MLX5DV_CONTEXT_XFRM_FLAGS_ESP_AES_GCM_SPI_RSS_ONLY)
+#endif
+
 struct mlx5_args {
        int cqe_comp;
        int txq_inline;
diff --git a/drivers/net/mlx5/mlx5.h b/drivers/net/mlx5/mlx5.h
index e6a69b823..c6a01d972 100644
--- a/drivers/net/mlx5/mlx5.h
+++ b/drivers/net/mlx5/mlx5.h
@@ -117,6 +117,7 @@ struct priv {
        unsigned int isolated:1; /* Whether isolated mode is enabled. */
        unsigned int tx_vec_en:1; /* Whether Tx vector is enabled. */
        unsigned int rx_vec_en:1; /* Whether Rx vector is enabled. */
+       unsigned int ipsec_en:1; /* Whether IPsec is enabled. */
        unsigned int counter_set_supported:1; /* Counter set is supported. */
        /* Whether Tx offloads for tunneled packets are supported. */
        unsigned int max_tso_payload_sz; /* Maximum TCP payload for TSO. */
diff --git a/drivers/net/mlx5/mlx5_ethdev.c b/drivers/net/mlx5/mlx5_ethdev.c
index ca9ad0fef..f0c7fba43 100644
--- a/drivers/net/mlx5/mlx5_ethdev.c
+++ b/drivers/net/mlx5/mlx5_ethdev.c
@@ -680,6 +680,10 @@ mlx5_dev_infos_get(struct rte_eth_dev *dev, struct 
rte_eth_dev_info *info)
                         DEV_TX_OFFLOAD_TCP_CKSUM);
        if (priv->tso)
                info->tx_offload_capa |= DEV_TX_OFFLOAD_TCP_TSO;
+       if (priv->ipsec_en) {
+               info->tx_offload_capa |= DEV_TX_OFFLOAD_SECURITY;
+               info->rx_offload_capa |= DEV_RX_OFFLOAD_SECURITY;
+       }
        if (priv->tunnel_en)
                info->tx_offload_capa |= (DEV_TX_OFFLOAD_OUTER_IPV4_CKSUM |
                                          DEV_TX_OFFLOAD_VXLAN_TNL_TSO |
diff --git a/drivers/net/mlx5/mlx5_prm.h b/drivers/net/mlx5/mlx5_prm.h
index 2de310bcb..bd6270671 100644
--- a/drivers/net/mlx5/mlx5_prm.h
+++ b/drivers/net/mlx5/mlx5_prm.h
@@ -342,4 +342,43 @@ mlx5_flow_mark_get(uint32_t val)
 #endif
 }
 
+/* IPsec offloads elements. */
+
+/* IPsec Rx code. */
+#define MLX5_IPSEC_RX_DECRYPTED 0x11
+#define MLX5_IPSEC_RX_AUTH_FAIL 0x12
+
+/* IPsec Tx code. */
+#define MLX5_IPSEC_TX_OFFLOAD 0x8
+
+/* Metadata length . */
+#define MLX5_METADATA_LEN 8
+
+/* Packet IPsec Rx metadata. */
+struct mlx5_rx_pkt_ipsec_metadata {
+       uint8_t reserved;
+       rte_be32_t sa_handle;
+} __rte_packed;
+
+/* Tx packet Metadata. */
+struct mlx5_tx_pkt_ipsec_metadata {
+       rte_be16_t mss_inv; /** MSS fixed point, used only in LSO. */
+       rte_be16_t seq; /** LSBs of the first TCP seq, only in LSO. */
+       uint8_t esp_next_proto; /* Next protocol of ESP. */
+} __rte_packed;
+
+/* Packet Metadata. */
+struct mlx5_pkt_metadata {
+       uint8_t syndrome;
+       union {
+               uint8_t raw[5];
+               struct mlx5_rx_pkt_ipsec_metadata rx;
+               struct mlx5_tx_pkt_ipsec_metadata tx;
+       } __rte_packed;
+       rte_be16_t ethertype;
+} __rte_packed;
+
+static_assert(sizeof(struct mlx5_pkt_metadata) == MLX5_METADATA_LEN,
+             "wrong metadata size detected.");
+
 #endif /* RTE_PMD_MLX5_PRM_H_ */
diff --git a/drivers/net/mlx5/mlx5_rxtx.c b/drivers/net/mlx5/mlx5_rxtx.c
index 28c0ad8ab..91ceb3c55 100644
--- a/drivers/net/mlx5/mlx5_rxtx.c
+++ b/drivers/net/mlx5/mlx5_rxtx.c
@@ -344,6 +344,7 @@ mlx5_tx_burst(void *dpdk_txq, struct rte_mbuf **pkts, 
uint16_t pkts_n)
        unsigned int j = 0;
        unsigned int k = 0;
        uint16_t max_elts;
+       const unsigned int ipsec_en = txq->ipsec_en;
        uint16_t max_wqe;
        unsigned int comp;
        volatile struct mlx5_wqe_ctrl *last_wqe = NULL;
@@ -417,14 +418,43 @@ mlx5_tx_burst(void *dpdk_txq, struct rte_mbuf **pkts, 
uint16_t pkts_n)
                            rte_pktmbuf_mtod(*(pkts + 1), volatile void *));
                cs_flags = txq_ol_cksum_to_cs(txq, buf);
                raw = ((uint8_t *)(uintptr_t)wqe) + 2 * MLX5_WQE_DWORD_SIZE;
-               /* Replace the Ethernet type by the VLAN if necessary. */
+               addr += 2;
+               length -= 2;
+               /* Handle IPsec offload. */
+               if (ipsec_en && (buf->ol_flags & PKT_TX_SEC_OFFLOAD)) {
+                       struct mlx5_pkt_metadata mdata = {
+                               .syndrome = MLX5_IPSEC_TX_OFFLOAD,
+                               .tx.esp_next_proto = buf->inner_esp_next_proto,
+                       };
+                       unsigned int len = 2 * ETHER_ADDR_LEN - 2;
+                       rte_be16_t ethertype =
+                               rte_cpu_to_be_16(ETHER_TYPE_MLNX);
+
+                       if (buf->ol_flags & PKT_TX_TCP_CKSUM) {
+                               txq->stats.oerrors++;
+                               break;
+                       }
+                       /* Copy Destination and source mac address. */
+                       memcpy((uint8_t *)raw, ((uint8_t *)addr), len);
+                       raw += len;
+                       addr += len;
+                       length -= len;
+                       /* Copy Metadata. */
+                       memcpy((uint8_t *)raw, &ethertype, 2);
+                       memcpy((uint8_t *)raw + 2, &mdata,
+                              MLX5_METADATA_LEN - 2);
+                       memcpy((uint8_t *)raw + MLX5_METADATA_LEN,
+                              (uint8_t *)addr, 2);
+                       addr += 2;
+                       len -= 2;
+                       raw += MLX5_METADATA_LEN + 2;
+                       pkt_inline_sz += MLX5_METADATA_LEN;
+               }
                if (buf->ol_flags & PKT_TX_VLAN_PKT) {
                        uint32_t vlan = rte_cpu_to_be_32(0x81000000 |
                                                         buf->vlan_tci);
                        unsigned int len = 2 * ETHER_ADDR_LEN - 2;
 
-                       addr += 2;
-                       length -= 2;
                        /* Copy Destination and source mac address. */
                        memcpy((uint8_t *)raw, ((uint8_t *)addr), len);
                        /* Copy VLAN. */
@@ -435,10 +465,10 @@ mlx5_tx_burst(void *dpdk_txq, struct rte_mbuf **pkts, 
uint16_t pkts_n)
                        addr += len + 2;
                        length -= (len + 2);
                } else {
-                       memcpy((uint8_t *)raw, ((uint8_t *)addr) + 2,
+                       memcpy((uint8_t *)raw, ((uint8_t *)addr),
                               MLX5_WQE_DWORD_SIZE);
-                       length -= pkt_inline_sz;
-                       addr += pkt_inline_sz;
+                       length -= MLX5_WQE_DWORD_SIZE;
+                       addr += MLX5_WQE_DWORD_SIZE;
                }
                raw += MLX5_WQE_DWORD_SIZE;
                if (txq->tso_en) {
@@ -1572,6 +1602,59 @@ mlx5_tx_burst_empw(void *dpdk_txq, struct rte_mbuf 
**pkts, uint16_t pkts_n)
 }
 
 /**
+ * Process an IPsec encrypted packet.
+ *
+ * @param pkt
+ *   Pointer to the first segment of the packet.
+ * @param len
+ *   Already gathered packet length.
+ *
+ * @return
+ *   new packet length on success, 0 on failure.
+ */
+static __rte_noinline int
+mlx5_rx_handle_ipsec(struct rte_mbuf *pkt, int len)
+{
+       struct mlx5_pkt_metadata *mdata;
+       struct ether_hdr *eth;
+
+       if (len < ETHER_HDR_LEN + MLX5_METADATA_LEN)
+               return 0;
+       eth = rte_pktmbuf_mtod(pkt, struct ether_hdr *);
+       if (eth->ether_type != rte_cpu_to_be_16(ETHER_TYPE_MLNX))
+               goto out;
+       /* Use the metadata */
+       mdata = rte_pktmbuf_mtod_offset(pkt, struct mlx5_pkt_metadata *,
+                                       ETHER_HDR_LEN);
+       if (mdata->syndrome == MLX5_IPSEC_RX_DECRYPTED)
+               pkt->ol_flags |= PKT_RX_SEC_OFFLOAD;
+       else if (mdata->syndrome == MLX5_IPSEC_RX_AUTH_FAIL)
+               pkt->ol_flags |= PKT_RX_SEC_OFFLOAD_FAILED;
+       else
+               return 0;
+       /*
+        * Move the data from the buffer:
+        *
+        *   6B    6B     2B     6B    2B
+        * +-----+-----+-------+----+-------+
+        * | DST | SRC | MType | MD | Etype |
+        * +-----+-----+-------+----+-------+
+        *
+        * to:
+        *     6B       6B    6B    2B
+        * +---------+-----+-----+-------+
+        * | Garbage | DST | SRC | EType |
+        * +---------+-----+-----+-------+
+        */
+       memmove((void *)((uintptr_t)mdata - 6), eth, 2 * ETHER_ADDR_LEN);
+       /* Ethertype is already in its new place */
+       rte_pktmbuf_adj(pkt, MLX5_METADATA_LEN);
+       len -= MLX5_METADATA_LEN;
+out:
+       return len;
+}
+
+/**
  * Translate RX completion flags to packet type.
  *
  * @param[in] cqe
@@ -1772,6 +1855,7 @@ mlx5_rx_burst(void *dpdk_rxq, struct rte_mbuf **pkts, 
uint16_t pkts_n)
        const unsigned int wqe_cnt = (1 << rxq->elts_n) - 1;
        const unsigned int cqe_cnt = (1 << rxq->cqe_n) - 1;
        const unsigned int sges_n = rxq->sges_n;
+       const unsigned int ipsec_en = rxq->ipsec_en;
        struct rte_mbuf *pkt = NULL;
        struct rte_mbuf *seg = NULL;
        volatile struct mlx5_cqe *cqe =
@@ -1864,6 +1948,14 @@ mlx5_rx_burst(void *dpdk_rxq, struct rte_mbuf **pkts, 
uint16_t pkts_n)
                        }
                        if (rxq->crc_present)
                                len -= ETHER_CRC_LEN;
+                       if (ipsec_en) {
+                               len = mlx5_rx_handle_ipsec(pkt, len);
+                               if (unlikely(len == 0)) {
+                                       rte_mbuf_raw_free(rep);
+                                       ++rxq->stats.idropped;
+                                       goto skip;
+                               }
+                       }
                        PKT_LEN(pkt) = len;
                }
                DATA_LEN(rep) = DATA_LEN(seg);
diff --git a/drivers/net/mlx5/mlx5_rxtx.h b/drivers/net/mlx5/mlx5_rxtx.h
index b8c7925a3..e219d01ee 100644
--- a/drivers/net/mlx5/mlx5_rxtx.h
+++ b/drivers/net/mlx5/mlx5_rxtx.h
@@ -115,7 +115,8 @@ struct mlx5_rxq_data {
        unsigned int rss_hash:1; /* RSS hash result is enabled. */
        unsigned int mark:1; /* Marked flow available on the queue. */
        unsigned int pending_err:1; /* CQE error needs to be handled. */
-       unsigned int :14; /* Remaining bits. */
+       unsigned int ipsec_en:1; /* IPsec is enabled on this queue. */
+       unsigned int :13; /* Remaining bits. */
        volatile uint32_t *rq_db;
        volatile uint32_t *cq_db;
        uint16_t port_id;
@@ -195,6 +196,7 @@ struct mlx5_txq_data {
        uint16_t tunnel_en:1;
        /* When set TX offload for tunneled packets are supported. */
        uint16_t mpw_hdr_dseg:1; /* Enable DSEGs in the title WQEBB. */
+       uint16_t ipsec_en:1; /* Whether IPsec Tx offload is enabled. */
        uint16_t max_inline; /* Multiple of RTE_CACHE_LINE_SIZE to inline. */
        uint16_t inline_max_packet_sz; /* Max packet size for inlining. */
        uint16_t mr_cache_idx; /* Index of last hit entry. */
diff --git a/drivers/net/mlx5/mlx5_txq.c b/drivers/net/mlx5/mlx5_txq.c
index a786a6b63..4d53c6da5 100644
--- a/drivers/net/mlx5/mlx5_txq.c
+++ b/drivers/net/mlx5/mlx5_txq.c
@@ -646,6 +646,7 @@ mlx5_priv_txq_new(struct priv *priv, uint16_t idx, uint16_t 
desc,
        }
        if (priv->tunnel_en)
                tmpl->txq.tunnel_en = 1;
+       tmpl->txq.ipsec_en = priv->ipsec_en;
        tmpl->txq.elts =
                (struct rte_mbuf *(*)[1 << tmpl->txq.elts_n])(tmpl + 1);
        tmpl->txq.stats.idx = idx;
-- 
2.11.0

Reply via email to