@@ -38,6 +38,11 @@ DPDK Release 23.11
which also added support for standard atomics
(Ref: https://releases.llvm.org/3.6.0/tools/clang/docs/ReleaseNotes.html)
+ * **Added inline IPsec offload feature for NFP PMD.**
+
+ Added the inline IPsec offload feature based on the security framework for
+ NFP PMD.
+
New Features
------------
@@ -33,8 +33,9 @@ sources = files(
'nfp_ethdev_vf.c',
'nfp_ethdev.c',
'nfp_flow.c',
+ 'nfp_ipsec.c',
'nfp_logs.c',
'nfp_mtr.c',
)
-deps += ['hash']
+deps += ['hash', 'security']
@@ -1200,6 +1200,7 @@ nfp_net_tx_desc_limits(struct nfp_net_hw *hw,
int
nfp_net_infos_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)
{
+ uint32_t cap_extend;
uint16_t min_rx_desc;
uint16_t max_rx_desc;
uint16_t min_tx_desc;
@@ -1256,6 +1257,12 @@ nfp_net_infos_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)
if (hw->cap & NFP_NET_CFG_CTRL_GATHER)
dev_info->tx_offload_capa |= RTE_ETH_TX_OFFLOAD_MULTI_SEGS;
+ cap_extend = nn_cfg_readl(hw, NFP_NET_CFG_CAP_WORD1);
+ if ((cap_extend & NFP_NET_CFG_CTRL_IPSEC) != 0) {
+ dev_info->tx_offload_capa |= RTE_ETH_TX_OFFLOAD_SECURITY;
+ dev_info->rx_offload_capa |= RTE_ETH_RX_OFFLOAD_SECURITY;
+ }
+
dev_info->default_rxconf = (struct rte_eth_rxconf) {
.rx_thresh = {
.pthresh = DEFAULT_RX_PTHRESH,
@@ -172,6 +172,8 @@ struct nfp_net_hw {
uint8_t nfp_idx;
struct nfp_net_tlv_caps tlv_caps;
+
+ struct nfp_net_ipsec_data *ipsec_data;
};
struct nfp_net_adapter {
@@ -238,6 +238,9 @@ struct nfp_net_fw_ver {
*/
#define NFP_NET_CFG_CTRL_WORD1 0x0098
#define NFP_NET_CFG_CTRL_PKT_TYPE (0x1 << 0)
+#define NFP_NET_CFG_CTRL_IPSEC (0x1 << 1) /**< IPsec offload */
+#define NFP_NET_CFG_CTRL_IPSEC_SM_LOOKUP (0x1 << 3) /**< SA short match lookup */
+#define NFP_NET_CFG_CTRL_IPSEC_LM_LOOKUP (0x1 << 4) /**< SA long match lookup */
#define NFP_NET_CFG_CAP_WORD1 0x00a4
@@ -18,6 +18,7 @@
#include "nfpcore/nfp6000_pcie.h"
#include "nfp_cpp_bridge.h"
+#include "nfp_ipsec.h"
#include "nfp_logs.h"
static int
@@ -140,6 +141,10 @@ nfp_net_start(struct rte_eth_dev *dev)
if ((cap_extend & NFP_NET_CFG_CTRL_PKT_TYPE) != 0)
ctrl_extend = NFP_NET_CFG_CTRL_PKT_TYPE;
+ if ((cap_extend & NFP_NET_CFG_CTRL_IPSEC) != 0)
+ ctrl_extend |= NFP_NET_CFG_CTRL_IPSEC_SM_LOOKUP
+ | NFP_NET_CFG_CTRL_IPSEC_LM_LOOKUP;
+
update = NFP_NET_CFG_UPDATE_GEN;
if (nfp_net_ext_reconfig(hw, ctrl_extend, update) < 0)
return -EIO;
@@ -278,6 +283,9 @@ nfp_net_close(struct rte_eth_dev *dev)
nfp_net_close_rx_queue(dev);
+ /* Clear ipsec */
+ nfp_ipsec_uninit(dev);
+
/* Cancel possible impending LSC work here before releasing the port*/
rte_eal_alarm_cancel(nfp_net_dev_interrupt_delayed_handler,
(void *)dev);
@@ -555,6 +563,12 @@ nfp_net_init(struct rte_eth_dev *eth_dev)
return err;
}
+ err = nfp_ipsec_init(eth_dev);
+ if (err != 0) {
+ PMD_INIT_LOG(ERR, "Failed to init IPsec module");
+ return err;
+ }
+
nfp_net_ethdev_ops_mount(hw, eth_dev);
hw->eth_xstats_base = rte_malloc("rte_eth_xstat", sizeof(struct rte_eth_xstat) *
@@ -867,6 +881,7 @@ nfp_init_app_fw_nic(struct nfp_pf_dev *pf_dev,
if (app_fw_nic->ports[i] && app_fw_nic->ports[i]->eth_dev) {
struct rte_eth_dev *tmp_dev;
tmp_dev = app_fw_nic->ports[i]->eth_dev;
+ nfp_ipsec_uninit(tmp_dev);
rte_eth_dev_release_port(tmp_dev);
app_fw_nic->ports[i] = NULL;
}
new file mode 100644
@@ -0,0 +1,131 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (c) 2023 Corigine Systems, Inc.
+ * All rights reserved.
+ */
+
+#include "nfp_ipsec.h"
+
+#include <rte_malloc.h>
+#include <rte_security_driver.h>
+
+#include <ethdev_driver.h>
+#include <ethdev_pci.h>
+
+#include "nfp_common.h"
+#include "nfp_ctrl.h"
+#include "nfp_logs.h"
+#include "nfp_rxtx.h"
+
+static const struct rte_security_ops nfp_security_ops;
+
+static int
+nfp_ipsec_ctx_create(struct rte_eth_dev *dev,
+ struct nfp_net_ipsec_data *data)
+{
+ struct rte_security_ctx *ctx;
+ static const struct rte_mbuf_dynfield pkt_md_dynfield = {
+ .name = "nfp_ipsec_crypto_pkt_metadata",
+ .size = sizeof(struct nfp_tx_ipsec_desc_msg),
+ .align = __alignof__(struct nfp_tx_ipsec_desc_msg),
+ };
+
+ ctx = rte_zmalloc("security_ctx",
+ sizeof(struct rte_security_ctx), 0);
+ if (ctx == NULL) {
+ PMD_INIT_LOG(ERR, "Failed to malloc security_ctx");
+ return -ENOMEM;
+ }
+
+ ctx->device = dev;
+ ctx->ops = &nfp_security_ops;
+ ctx->sess_cnt = 0;
+ dev->security_ctx = ctx;
+
+ data->pkt_dynfield_offset = rte_mbuf_dynfield_register(&pkt_md_dynfield);
+ if (data->pkt_dynfield_offset < 0) {
+ PMD_INIT_LOG(ERR, "Failed to register mbuf esn_dynfield");
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+int
+nfp_ipsec_init(struct rte_eth_dev *dev)
+{
+ int ret;
+ uint32_t cap_extend;
+ struct nfp_net_hw *hw;
+ struct nfp_net_ipsec_data *data;
+
+ hw = NFP_NET_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+ cap_extend = nn_cfg_readl(hw, NFP_NET_CFG_CAP_WORD1);
+ if ((cap_extend & NFP_NET_CFG_CTRL_IPSEC) == 0) {
+ PMD_INIT_LOG(INFO, "Unsupported IPsec extend capability");
+ return 0;
+ }
+
+ data = rte_zmalloc("ipsec_data", sizeof(struct nfp_net_ipsec_data), 0);
+ if (data == NULL) {
+ PMD_INIT_LOG(ERR, "Failed to malloc ipsec_data");
+ return -ENOMEM;
+ }
+
+ data->pkt_dynfield_offset = -1;
+ data->sa_free_cnt = NFP_NET_IPSEC_MAX_SA_CNT;
+ hw->ipsec_data = data;
+
+ ret = nfp_ipsec_ctx_create(dev, data);
+ if (ret != 0) {
+ PMD_INIT_LOG(ERR, "Failed to create IPsec ctx");
+ goto ipsec_cleanup;
+ }
+
+ return 0;
+
+ipsec_cleanup:
+ nfp_ipsec_uninit(dev);
+
+ return ret;
+}
+
+static void
+nfp_ipsec_ctx_destroy(struct rte_eth_dev *dev)
+{
+ if (dev->security_ctx != NULL)
+ rte_free(dev->security_ctx);
+}
+
+void
+nfp_ipsec_uninit(struct rte_eth_dev *dev)
+{
+ uint16_t i;
+ uint32_t cap_extend;
+ struct nfp_net_hw *hw;
+ struct nfp_ipsec_session *priv_session;
+
+ hw = NFP_NET_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+ cap_extend = nn_cfg_readl(hw, NFP_NET_CFG_CAP_WORD1);
+ if ((cap_extend & NFP_NET_CFG_CTRL_IPSEC) == 0) {
+ PMD_INIT_LOG(INFO, "Unsupported IPsec extend capability");
+ return;
+ }
+
+ nfp_ipsec_ctx_destroy(dev);
+
+ if (hw->ipsec_data == NULL) {
+ PMD_INIT_LOG(INFO, "IPsec data is NULL!");
+ return;
+ }
+
+ for (i = 0; i < NFP_NET_IPSEC_MAX_SA_CNT; i++) {
+ priv_session = hw->ipsec_data->sa_entries[i];
+ if (priv_session != NULL)
+ memset(priv_session, 0, sizeof(struct nfp_ipsec_session));
+ }
+
+ rte_free(hw->ipsec_data);
+}
+
new file mode 100644
@@ -0,0 +1,174 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (c) 2023 Corigine Systems, Inc.
+ * All rights reserved.
+ */
+
+#ifndef __NFP_IPSEC_H__
+#define __NFP_IPSEC_H__
+
+#include <rte_security.h>
+
+#define NFP_NET_IPSEC_MAX_SA_CNT (16 * 1024)
+
+struct ipsec_aesgcm { /**< AES-GCM-ESP fields */
+ uint32_t salt; /**< Initialized with SA */
+ uint32_t iv[2]; /**< Firmware use only */
+ uint32_t cntrl;
+ uint32_t zeros[4]; /**< Init to 0 with SA */
+ uint32_t len_auth[2]; /**< Firmware use only */
+ uint32_t len_cipher[2];
+ uint32_t spare[4];
+};
+
+struct sa_ctrl_word {
+ uint32_t hash :4; /**< From nfp_ipsec_hash_type */
+ uint32_t cimode :4; /**< From nfp_ipsec_cipher_mode */
+ uint32_t cipher :4; /**< From nfp_ipsec_cipher */
+ uint32_t mode :2; /**< From nfp_ipsec_mode */
+ uint32_t proto :2; /**< From nfp_ipsec_prot */
+ uint32_t spare :1; /**< Should be 0 */
+ uint32_t ena_arw:1; /**< Anti-Replay Window */
+ uint32_t ext_seq:1; /**< 64-bit Sequence Num */
+ uint32_t ext_arw:1; /**< 64b Anti-Replay Window */
+ uint32_t spare1 :9; /**< Must be set to 0 */
+ uint32_t encap_dsbl:1; /**< Encap/decap disable */
+ uint32_t gen_seq:1; /**< Firmware Generate Seq #'s */
+ uint32_t spare2 :1; /**< Must be set to 0 */
+};
+
+union nfp_ip_addr {
+ struct in6_addr v6;
+ struct in_addr v4;
+};
+
+struct ipsec_add_sa {
+ uint32_t cipher_key[8]; /**< Cipher Key */
+ union {
+ uint32_t auth_key[16]; /**< Authentication Key */
+ struct ipsec_aesgcm aesgcm_fields;
+ };
+ struct sa_ctrl_word ctrl_word;
+ uint32_t spi; /**< SPI Value */
+ uint16_t pmtu_limit; /**< PMTU Limit */
+ uint32_t spare :1;
+ uint32_t frag_check :1; /**< Stateful fragment checking flag */
+ uint32_t bypass_DSCP:1; /**< Bypass DSCP Flag */
+ uint32_t df_ctrl :2; /**< DF Control bits */
+ uint32_t ipv6 :1; /**< Outbound IPv6 addr format */
+ uint32_t udp_enable :1; /**< Add/Remove UDP header for NAT */
+ uint32_t tfc_enable :1; /**< Traffic Flw Confidentiality */
+ uint8_t spare1;
+ uint32_t soft_byte_cnt; /**< Soft lifetime byte count */
+ uint32_t hard_byte_cnt; /**< Hard lifetime byte count */
+ union nfp_ip_addr src_ip; /**< Src IP addr */
+ union nfp_ip_addr dst_ip; /**< Dst IP addr */
+ uint16_t natt_dst_port; /**< NAT-T UDP Header dst port */
+ uint16_t natt_src_port; /**< NAT-T UDP Header src port */
+ uint32_t soft_lifetime_limit; /**< Soft lifetime time limit */
+ uint32_t hard_lifetime_limit; /**< Hard lifetime time limit */
+ uint32_t sa_time_lo; /**< SA creation time lower 32bits, Ucode fills this in */
+ uint32_t sa_time_hi; /**< SA creation time high 32bits, Ucode fills this in */
+ uint16_t spare2;
+ uint16_t tfc_padding; /**< Traffic Flow Confidential Pad */
+};
+
+struct ipsec_inv_sa {
+ uint32_t spare;
+};
+
+struct ipsec_discard_stats {
+ uint32_t discards_auth; /**< Auth failures */
+ uint32_t discards_unsupported; /**< Unsupported crypto mode */
+ uint32_t discards_alignment; /**< Alignment error */
+ uint32_t discards_hard_bytelimit; /**< Hard byte Count limit */
+ uint32_t discards_seq_num_wrap; /**< Sequ Number wrap */
+ uint32_t discards_pmtu_exceeded; /**< PMTU Limit exceeded*/
+ uint32_t discards_arw_old_seq; /**< Anti-Replay seq small */
+ uint32_t discards_arw_replay; /**< Anti-Replay seq rcvd */
+ uint32_t discards_ctrl_word; /**< Bad SA Control word */
+ uint32_t discards_ip_hdr_len; /**< Hdr offset from too high */
+ uint32_t discards_eop_buf; /**< No EOP buffer */
+ uint32_t ipv4_id_counter; /**< IPv4 ID field counter */
+ uint32_t discards_isl_fail; /**< Inbound SPD Lookup failure */
+ uint32_t discards_ext_unfound; /**< Ext header end */
+ uint32_t discards_max_ext_hdrs; /**< Max ext header */
+ uint32_t discards_non_ext_hdrs; /**< Non-extension headers */
+ uint32_t discards_ext_hdr_too_big; /**< Ext header chain */
+ uint32_t discards_hard_timelimit; /**< Time Limit */
+};
+
+struct ipsec_get_sa_stats {
+ uint32_t seq_lo; /**< Sequence Number (low 32bits) */
+ uint32_t seq_high; /**< Sequence Number (high 32bits)*/
+ uint32_t arw_counter_lo; /**< Anti-replay wndw cntr */
+ uint32_t arw_counter_high; /**< Anti-replay wndw cntr */
+ uint32_t arw_bitmap_lo; /**< Anti-replay wndw bitmap */
+ uint32_t arw_bitmap_high; /**< Anti-replay wndw bitmap */
+ uint32_t spare:1;
+ uint32_t soft_byte_exceeded :1; /**< Soft lifetime byte cnt exceeded*/
+ uint32_t hard_byte_exceeded :1; /**< Hard lifetime byte cnt exceeded*/
+ uint32_t soft_time_exceeded :1; /**< Soft lifetime time limit exceeded*/
+ uint32_t hard_time_exceeded :1; /**< Hard lifetime time limit exceeded*/
+ uint32_t spare1:27;
+ uint32_t lifetime_byte_count;
+ uint32_t pkt_count;
+ struct ipsec_discard_stats sa_discard_stats;
+};
+
+struct ipsec_get_seq {
+ uint32_t seq_nums; /**< Sequence numbers to allocate */
+ uint32_t seq_num_low; /**< Return start seq num 31:00 */
+ uint32_t seq_num_hi; /**< Return start seq num 63:32 */
+};
+
+struct nfp_ipsec_msg {
+ union {
+ struct {
+ /** NFP IPsec SA cmd message codes */
+ uint16_t cmd;
+ /** NFP IPsec SA response message */
+ uint16_t rsp;
+ /** NFP IPsec SA index in driver SA table */
+ uint16_t sa_idx;
+ /** Reserved */
+ uint16_t spare;
+ union {
+ /** IPsec configure message for add SA */
+ struct ipsec_add_sa cfg_add_sa;
+ /** IPsec configure message for del SA */
+ struct ipsec_inv_sa cfg_inv_sa;
+ /** IPsec configure message for get SA stats */
+ struct ipsec_get_sa_stats cfg_get_stats;
+ /** IPsec configure message for get SA seq numbers */
+ struct ipsec_get_seq cfg_get_seq;
+ };
+ };
+ uint32_t raw[64];
+ };
+};
+
+struct nfp_ipsec_session {
+ /** Opaque user defined data */
+ void *user_data;
+ /** NFP sa_entries database parameter index */
+ uint32_t sa_index;
+ /** Point to physical ports ethernet device */
+ struct rte_eth_dev *dev;
+ /** SA related NPF configuration data */
+ struct ipsec_add_sa msg;
+ /** Security association configuration data */
+ struct rte_security_ipsec_xform ipsec;
+ /** Security session action type */
+ enum rte_security_session_action_type action;
+} __rte_cache_aligned;
+
+struct nfp_net_ipsec_data {
+ int pkt_dynfield_offset;
+ uint32_t sa_free_cnt;
+ struct nfp_ipsec_session *sa_entries[NFP_NET_IPSEC_MAX_SA_CNT];
+};
+
+int nfp_ipsec_init(struct rte_eth_dev *dev);
+void nfp_ipsec_uninit(struct rte_eth_dev *dev);
+
+#endif /* __NFP_IPSEC_H__ */
@@ -43,6 +43,18 @@ struct nfp_net_dp_buf {
struct rte_mbuf *mbuf;
};
+struct nfp_tx_ipsec_desc_msg {
+ uint32_t sa_idx; /**< SA index in driver table */
+ uint32_t enc; /**< IPsec enable flag */
+ union {
+ uint64_t value;
+ struct {
+ uint32_t low;
+ uint32_t hi;
+ };
+ } esn; /**< Extended Sequence Number */
+};
+
struct nfp_net_txq {
/** Backpointer to nfp_net structure */
struct nfp_net_hw *hw;