net/cnxk: support inline security setup for cn10k
authorNithin Dabilpuram <ndabilpuram@marvell.com>
Fri, 1 Oct 2021 13:40:11 +0000 (19:10 +0530)
committerJerin Jacob <jerinj@marvell.com>
Sat, 2 Oct 2021 13:45:05 +0000 (15:45 +0200)
Add support for inline inbound and outbound IPSec for SA create,
destroy and other NIX / CPT LF configurations.

This patch also changes dpdk-devbind.py to list new inline
device as misc device.

Signed-off-by: Nithin Dabilpuram <ndabilpuram@marvell.com>
Acked-by: Jerin Jacob <jerinj@marvell.com>
13 files changed:
doc/guides/nics/cnxk.rst
doc/guides/nics/features/cnxk.ini
doc/guides/nics/features/cnxk_vec.ini
doc/guides/nics/features/cnxk_vf.ini
doc/guides/rel_notes/release_21_11.rst
drivers/event/cnxk/cnxk_eventdev_adptr.c
drivers/net/cnxk/cn10k_ethdev.c
drivers/net/cnxk/cn10k_ethdev.h
drivers/net/cnxk/cn10k_ethdev_sec.c [new file with mode: 0644]
drivers/net/cnxk/cn10k_rx.h
drivers/net/cnxk/cn10k_tx.h
drivers/net/cnxk/meson.build
usertools/dpdk-devbind.py

index 90d27db..b542437 100644 (file)
@@ -34,6 +34,7 @@ Features of the CNXK Ethdev PMD are:
 - Vector Poll mode driver
 - Debug utilities - Context dump and error interrupt support
 - Support Rx interrupt
+- Inline IPsec processing support
 
 Prerequisites
 -------------
@@ -185,6 +186,74 @@ Runtime Config Options
 
       -a 0002:02:00.0,tag_as_xor=1
 
+- ``Max SPI for inbound inline IPsec`` (default ``255``)
+
+   Max SPI supported for inbound inline IPsec processing can be specified by
+   ``ipsec_in_max_spi`` ``devargs`` parameter.
+
+   For example::
+
+      -a 0002:02:00.0,ipsec_in_max_spi=128
+
+   With the above configuration, application can enable inline IPsec processing
+   for 128 inbound SAs (SPI 0-127).
+
+- ``Max SA's for outbound inline IPsec`` (default ``4096``)
+
+   Max number of SA's supported for outbound inline IPsec processing can be
+   specified by ``ipsec_out_max_sa`` ``devargs`` parameter.
+
+   For example::
+
+      -a 0002:02:00.0,ipsec_out_max_sa=128
+
+   With the above configuration, application can enable inline IPsec processing
+   for 128 outbound SAs.
+
+- ``Outbound CPT LF queue size`` (default ``8200``)
+
+   Size of Outbound CPT LF queue in number of descriptors can be specified by
+   ``outb_nb_desc`` ``devargs`` parameter.
+
+   For example::
+
+      -a 0002:02:00.0,outb_nb_desc=16384
+
+    With the above configuration, Outbound CPT LF will be created to accommodate
+    at max 16384 descriptors at any given time.
+
+- ``Outbound CPT LF count`` (default ``1``)
+
+   Number of CPT LF's to attach for Outbound processing can be specified by
+   ``outb_nb_crypto_qs`` ``devargs`` parameter.
+
+   For example::
+
+      -a 0002:02:00.0,outb_nb_crypto_qs=2
+
+   With the above confiuration, two CPT LF's are setup and distributed among
+   all the Tx queues for outbound processing.
+
+- ``Force using inline ipsec device for inbound`` (default ``0``)
+
+   In CN10K, in event mode, driver can work in two modes,
+
+   1. Inbound encrypted traffic received by probed ipsec inline device while
+      plain traffic post decryption is received by ethdev.
+
+   2. Both Inbound encrypted traffic and plain traffic post decryption are
+      received by ethdev.
+
+   By default event mode works without using inline device i.e mode ``2``.
+   This behaviour can be changed to pick mode ``1`` by using
+   ``force_inb_inl_dev`` ``devargs`` parameter.
+
+   For example::
+
+      -a 0002:02:00.0,force_inb_inl_dev=1 -a 0002:03:00.0,force_inb_inl_dev=1
+
+   With the above configuration, inbound encrypted traffic from both the ports
+   is received by ipsec inline device.
 
 .. note::
 
@@ -250,6 +319,39 @@ Example usage in testpmd::
    testpmd> flow create 0 ingress pattern eth / raw relative is 0 pattern \
           spec ab pattern mask ab offset is 4 / end actions queue index 1 / end
 
+Inline device support for CN10K
+-------------------------------
+
+CN10K HW provides a misc device Inline device that supports ethernet devices in
+providing following features.
+
+  - Aggregate all the inline IPsec inbound traffic from all the CN10K ethernet
+    devices to be processed by the single inline IPSec device. This allows
+    single rte security session to accept traffic from multiple ports.
+
+  - Support for event generation on outbound inline IPsec processing errors.
+
+  - Support CN106xx poll mode of operation for inline IPSec inbound processing.
+
+Inline IPsec device is identified by PCI PF vendid:devid ``177D:A0F0`` or
+VF ``177D:A0F1``.
+
+Runtime Config Options for inline device
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+- ``Max SPI for inbound inline IPsec`` (default ``255``)
+
+   Max SPI supported for inbound inline IPsec processing can be specified by
+   ``ipsec_in_max_spi`` ``devargs`` parameter.
+
+   For example::
+
+      -a 0002:1d:00.0,ipsec_in_max_spi=128
+
+   With the above configuration, application can enable inline IPsec processing
+   for 128 inbound SAs (SPI 0-127) for traffic aggregated on inline device.
+
+
 Debugging Options
 -----------------
 
index 5d45625..1ced3ee 100644 (file)
@@ -27,6 +27,7 @@ RSS hash             = Y
 RSS key update       = Y
 RSS reta update      = Y
 Inner RSS            = Y
+Inline protocol      = Y
 Flow control         = Y
 Jumbo frame          = Y
 Scattered Rx         = Y
index abf2b8d..12ca0a5 100644 (file)
@@ -26,6 +26,7 @@ RSS hash             = Y
 RSS key update       = Y
 RSS reta update      = Y
 Inner RSS            = Y
+Inline protocol      = Y
 Flow control         = Y
 Jumbo frame          = Y
 L3 checksum offload  = Y
index 7b4299f..139d9b9 100644 (file)
@@ -22,6 +22,7 @@ RSS hash             = Y
 RSS key update       = Y
 RSS reta update      = Y
 Inner RSS            = Y
+Inline protocol      = Y
 Jumbo frame          = Y
 Scattered Rx         = Y
 L3 checksum offload  = Y
index 9e10d28..0f20089 100644 (file)
@@ -98,6 +98,8 @@ New Features
 
   * Added rte_flow support for dual VLAN insert and strip actions.
   * Added rte_tm support.
+  * Added support for Inline IPsec for CN9K event mode and CN10K
+    poll mode and event mode.
 
 * **Updated Marvell cnxk crypto PMD.**
 
index baf2f2a..a34efbb 100644 (file)
@@ -123,7 +123,9 @@ cnxk_sso_rxq_enable(struct cnxk_eth_dev *cnxk_eth_dev, uint16_t rq_id,
                    uint16_t port_id, const struct rte_event *ev,
                    uint8_t custom_flowid)
 {
+       struct roc_nix *nix = &cnxk_eth_dev->nix;
        struct roc_nix_rq *rq;
+       int rc;
 
        rq = &cnxk_eth_dev->rqs[rq_id];
        rq->sso_ena = 1;
@@ -140,7 +142,24 @@ cnxk_sso_rxq_enable(struct cnxk_eth_dev *cnxk_eth_dev, uint16_t rq_id,
                rq->tag_mask |= ev->flow_id;
        }
 
-       return roc_nix_rq_modify(&cnxk_eth_dev->nix, rq, 0);
+       rc = roc_nix_rq_modify(&cnxk_eth_dev->nix, rq, 0);
+       if (rc)
+               return rc;
+
+       if (rq_id == 0 && roc_nix_inl_inb_is_enabled(nix)) {
+               uint32_t sec_tag_const;
+
+               /* IPSec tag const is 8-bit left shifted value of tag_mask
+                * as it applies to bit 32:8 of tag only.
+                */
+               sec_tag_const = rq->tag_mask >> 8;
+               rc = roc_nix_inl_inb_tag_update(nix, sec_tag_const,
+                                               ev->sched_type);
+               if (rc)
+                       plt_err("Failed to set tag conf for ipsec, rc=%d", rc);
+       }
+
+       return rc;
 }
 
 static int
@@ -186,6 +205,7 @@ cnxk_sso_rx_adapter_queue_add(
                rox_nix_fc_npa_bp_cfg(&cnxk_eth_dev->nix,
                                      rxq_sp->qconf.mp->pool_id, true,
                                      dev->force_ena_bp);
+               cnxk_eth_dev->nb_rxq_sso++;
        }
 
        if (rc < 0) {
@@ -196,6 +216,14 @@ cnxk_sso_rx_adapter_queue_add(
 
        dev->rx_offloads |= cnxk_eth_dev->rx_offload_flags;
 
+       /* Switch to use PF/VF's NIX LF instead of inline device for inbound
+        * when all the RQ's are switched to event dev mode. We do this only
+        * when using inline device is not forced by dev args.
+        */
+       if (!cnxk_eth_dev->inb.force_inl_dev &&
+           cnxk_eth_dev->nb_rxq_sso == cnxk_eth_dev->nb_rxq)
+               cnxk_nix_inb_mode_set(cnxk_eth_dev, false);
+
        return 0;
 }
 
@@ -220,12 +248,18 @@ cnxk_sso_rx_adapter_queue_del(const struct rte_eventdev *event_dev,
                rox_nix_fc_npa_bp_cfg(&cnxk_eth_dev->nix,
                                      rxq_sp->qconf.mp->pool_id, false,
                                      dev->force_ena_bp);
+               cnxk_eth_dev->nb_rxq_sso--;
        }
 
        if (rc < 0)
                plt_err("Failed to clear Rx adapter config port=%d, q=%d",
                        eth_dev->data->port_id, rx_queue_id);
 
+       /* Removing RQ from Rx adapter implies need to use
+        * inline device for CQ/Poll mode.
+        */
+       cnxk_nix_inb_mode_set(cnxk_eth_dev, true);
+
        return rc;
 }
 
index 7caec6c..fa2343c 100644 (file)
@@ -36,6 +36,9 @@ nix_rx_offload_flags(struct rte_eth_dev *eth_dev)
        if (!dev->ptype_disable)
                flags |= NIX_RX_OFFLOAD_PTYPE_F;
 
+       if (dev->rx_offloads & DEV_RX_OFFLOAD_SECURITY)
+               flags |= NIX_RX_OFFLOAD_SECURITY_F;
+
        return flags;
 }
 
@@ -101,6 +104,9 @@ nix_tx_offload_flags(struct rte_eth_dev *eth_dev)
        if ((dev->rx_offloads & DEV_RX_OFFLOAD_TIMESTAMP))
                flags |= NIX_TX_OFFLOAD_TSTAMP_F;
 
+       if (conf & DEV_TX_OFFLOAD_SECURITY)
+               flags |= NIX_TX_OFFLOAD_SECURITY_F;
+
        return flags;
 }
 
@@ -181,8 +187,11 @@ cn10k_nix_tx_queue_setup(struct rte_eth_dev *eth_dev, uint16_t qid,
                         const struct rte_eth_txconf *tx_conf)
 {
        struct cnxk_eth_dev *dev = cnxk_eth_pmd_priv(eth_dev);
+       struct roc_nix *nix = &dev->nix;
+       struct roc_cpt_lf *inl_lf;
        struct cn10k_eth_txq *txq;
        struct roc_nix_sq *sq;
+       uint16_t crypto_qid;
        int rc;
 
        RTE_SET_USED(socket);
@@ -198,11 +207,24 @@ cn10k_nix_tx_queue_setup(struct rte_eth_dev *eth_dev, uint16_t qid,
        txq = eth_dev->data->tx_queues[qid];
        txq->fc_mem = sq->fc;
        /* Store lmt base in tx queue for easy access */
-       txq->lmt_base = dev->nix.lmt_base;
+       txq->lmt_base = nix->lmt_base;
        txq->io_addr = sq->io_addr;
        txq->nb_sqb_bufs_adj = sq->nb_sqb_bufs_adj;
        txq->sqes_per_sqb_log2 = sq->sqes_per_sqb_log2;
 
+       /* Fetch CPT LF info for outbound if present */
+       if (dev->outb.lf_base) {
+               crypto_qid = qid % dev->outb.nb_crypto_qs;
+               inl_lf = dev->outb.lf_base + crypto_qid;
+
+               txq->cpt_io_addr = inl_lf->io_addr;
+               txq->cpt_fc = inl_lf->fc_addr;
+               txq->cpt_desc = inl_lf->nb_desc * 0.7;
+               txq->sa_base = (uint64_t)dev->outb.sa_base;
+               txq->sa_base |= eth_dev->data->port_id;
+               PLT_STATIC_ASSERT(ROC_NIX_INL_SA_BASE_ALIGN == BIT_ULL(16));
+       }
+
        nix_form_default_desc(dev, txq, qid);
        txq->lso_tun_fmt = dev->lso_tun_fmt;
        return 0;
@@ -215,6 +237,7 @@ cn10k_nix_rx_queue_setup(struct rte_eth_dev *eth_dev, uint16_t qid,
                         struct rte_mempool *mp)
 {
        struct cnxk_eth_dev *dev = cnxk_eth_pmd_priv(eth_dev);
+       struct cnxk_eth_rxq_sp *rxq_sp;
        struct cn10k_eth_rxq *rxq;
        struct roc_nix_rq *rq;
        struct roc_nix_cq *cq;
@@ -250,6 +273,15 @@ cn10k_nix_rx_queue_setup(struct rte_eth_dev *eth_dev, uint16_t qid,
        rxq->data_off = rq->first_skip;
        rxq->mbuf_initializer = cnxk_nix_rxq_mbuf_setup(dev);
 
+       /* Setup security related info */
+       if (dev->rx_offload_flags & NIX_RX_OFFLOAD_SECURITY_F) {
+               rxq->lmt_base = dev->nix.lmt_base;
+               rxq->sa_base = roc_nix_inl_inb_sa_base_get(&dev->nix,
+                                                          dev->inb.inl_dev);
+       }
+       rxq_sp = cnxk_eth_rxq_to_sp(rxq);
+       rxq->aura_handle = rxq_sp->qconf.mp->pool_id;
+
        /* Lookup mem */
        rxq->lookup_mem = cnxk_nix_fastpath_lookup_mem_get();
        return 0;
@@ -500,6 +532,8 @@ cn10k_nix_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
        nix_eth_dev_ops_override();
        npc_flow_ops_override();
 
+       cn10k_eth_sec_ops_override();
+
        /* Common probe */
        rc = cnxk_nix_probe(pci_drv, pci_dev);
        if (rc)
index 8b6e0f2..a888364 100644 (file)
@@ -5,6 +5,7 @@
 #define __CN10K_ETHDEV_H__
 
 #include <cnxk_ethdev.h>
+#include <cnxk_security.h>
 
 struct cn10k_eth_txq {
        uint64_t send_hdr_w0;
@@ -15,6 +16,10 @@ struct cn10k_eth_txq {
        rte_iova_t io_addr;
        uint16_t sqes_per_sqb_log2;
        int16_t nb_sqb_bufs_adj;
+       rte_iova_t cpt_io_addr;
+       uint64_t sa_base;
+       uint64_t *cpt_fc;
+       uint16_t cpt_desc;
        uint64_t cmd[4];
        uint64_t lso_tun_fmt;
 } __plt_cache_aligned;
@@ -30,12 +35,50 @@ struct cn10k_eth_rxq {
        uint32_t qmask;
        uint32_t available;
        uint16_t data_off;
+       uint64_t sa_base;
+       uint64_t lmt_base;
+       uint64_t aura_handle;
        uint16_t rq;
        struct cnxk_timesync_info *tstamp;
 } __plt_cache_aligned;
 
+/* Private data in sw rsvd area of struct roc_ot_ipsec_inb_sa */
+struct cn10k_inb_priv_data {
+       void *userdata;
+       struct cnxk_eth_sec_sess *eth_sec;
+};
+
+/* Private data in sw rsvd area of struct roc_ot_ipsec_outb_sa */
+struct cn10k_outb_priv_data {
+       void *userdata;
+       /* Rlen computation data */
+       struct cnxk_ipsec_outb_rlens rlens;
+       /* Back pinter to eth sec session */
+       struct cnxk_eth_sec_sess *eth_sec;
+       /* SA index */
+       uint32_t sa_idx;
+};
+
+struct cn10k_sec_sess_priv {
+       union {
+               struct {
+                       uint32_t sa_idx;
+                       uint8_t inb_sa : 1;
+                       uint8_t rsvd1 : 2;
+                       uint8_t roundup_byte : 5;
+                       uint8_t roundup_len;
+                       uint16_t partial_len;
+               };
+
+               uint64_t u64;
+       };
+} __rte_packed;
+
 /* Rx and Tx routines */
 void cn10k_eth_set_rx_function(struct rte_eth_dev *eth_dev);
 void cn10k_eth_set_tx_function(struct rte_eth_dev *eth_dev);
 
+/* Security context setup */
+void cn10k_eth_sec_ops_override(void);
+
 #endif /* __CN10K_ETHDEV_H__ */
diff --git a/drivers/net/cnxk/cn10k_ethdev_sec.c b/drivers/net/cnxk/cn10k_ethdev_sec.c
new file mode 100644 (file)
index 0000000..3ffd824
--- /dev/null
@@ -0,0 +1,426 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(C) 2021 Marvell.
+ */
+
+#include <rte_cryptodev.h>
+#include <rte_eventdev.h>
+#include <rte_security.h>
+#include <rte_security_driver.h>
+
+#include <cn10k_ethdev.h>
+#include <cnxk_security.h>
+
+static struct rte_cryptodev_capabilities cn10k_eth_sec_crypto_caps[] = {
+       {       /* AES GCM */
+               .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 = 32,
+                                       .increment = 8
+                               },
+                               .digest_size = {
+                                       .min = 16,
+                                       .max = 16,
+                                       .increment = 0
+                               },
+                               .aad_size = {
+                                       .min = 8,
+                                       .max = 12,
+                                       .increment = 4
+                               },
+                               .iv_size = {
+                                       .min = 12,
+                                       .max = 12,
+                                       .increment = 0
+                               }
+                       }, }
+               }, }
+       },
+       RTE_CRYPTODEV_END_OF_CAPABILITIES_LIST()
+};
+
+static const struct rte_security_capability cn10k_eth_sec_capabilities[] = {
+       {       /* IPsec Inline Protocol ESP Tunnel Ingress */
+               .action = RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL,
+               .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 = cn10k_eth_sec_crypto_caps,
+               .ol_flags = RTE_SECURITY_TX_OLOAD_NEED_MDATA
+       },
+       {       /* IPsec Inline Protocol ESP Tunnel Egress */
+               .action = RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL,
+               .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 = cn10k_eth_sec_crypto_caps,
+               .ol_flags = RTE_SECURITY_TX_OLOAD_NEED_MDATA
+       },
+       {
+               .action = RTE_SECURITY_ACTION_TYPE_NONE
+       }
+};
+
+static void
+cn10k_eth_sec_sso_work_cb(uint64_t *gw, void *args)
+{
+       struct rte_eth_event_ipsec_desc desc;
+       struct cn10k_sec_sess_priv sess_priv;
+       struct cn10k_outb_priv_data *priv;
+       struct roc_ot_ipsec_outb_sa *sa;
+       struct cpt_cn10k_res_s *res;
+       struct rte_eth_dev *eth_dev;
+       struct cnxk_eth_dev *dev;
+       uint16_t dlen_adj, rlen;
+       struct rte_mbuf *mbuf;
+       uintptr_t sa_base;
+       uintptr_t nixtx;
+       uint8_t port;
+
+       RTE_SET_USED(args);
+
+       switch ((gw[0] >> 28) & 0xF) {
+       case RTE_EVENT_TYPE_ETHDEV:
+               /* Event from inbound inline dev due to IPSEC packet bad L4 */
+               mbuf = (struct rte_mbuf *)(gw[1] - sizeof(struct rte_mbuf));
+               plt_nix_dbg("Received mbuf %p from inline dev inbound", mbuf);
+               rte_pktmbuf_free(mbuf);
+               return;
+       case RTE_EVENT_TYPE_CPU:
+               /* Check for subtype */
+               if (((gw[0] >> 20) & 0xFF) == CNXK_ETHDEV_SEC_OUTB_EV_SUB) {
+                       /* Event from outbound inline error */
+                       mbuf = (struct rte_mbuf *)gw[1];
+                       break;
+               }
+               /* Fall through */
+       default:
+               plt_err("Unknown event gw[0] = 0x%016lx, gw[1] = 0x%016lx",
+                       gw[0], gw[1]);
+               return;
+       }
+
+       /* Get ethdev port from tag */
+       port = gw[0] & 0xFF;
+       eth_dev = &rte_eth_devices[port];
+       dev = cnxk_eth_pmd_priv(eth_dev);
+
+       sess_priv.u64 = *rte_security_dynfield(mbuf);
+       /* Calculate dlen adj */
+       dlen_adj = mbuf->pkt_len - mbuf->l2_len;
+       rlen = (dlen_adj + sess_priv.roundup_len) +
+              (sess_priv.roundup_byte - 1);
+       rlen &= ~(uint64_t)(sess_priv.roundup_byte - 1);
+       rlen += sess_priv.partial_len;
+       dlen_adj = rlen - dlen_adj;
+
+       /* Find the res area residing on next cacheline after end of data */
+       nixtx = rte_pktmbuf_mtod(mbuf, uintptr_t) + mbuf->pkt_len + dlen_adj;
+       nixtx += BIT_ULL(7);
+       nixtx = (nixtx - 1) & ~(BIT_ULL(7) - 1);
+       res = (struct cpt_cn10k_res_s *)nixtx;
+
+       plt_nix_dbg("Outbound error, mbuf %p, sa_index %u, compcode %x uc %x",
+                   mbuf, sess_priv.sa_idx, res->compcode, res->uc_compcode);
+
+       sess_priv.u64 = *rte_security_dynfield(mbuf);
+
+       sa_base = dev->outb.sa_base;
+       sa = roc_nix_inl_ot_ipsec_outb_sa(sa_base, sess_priv.sa_idx);
+       priv = roc_nix_inl_ot_ipsec_outb_sa_sw_rsvd(sa);
+
+       memset(&desc, 0, sizeof(desc));
+
+       switch (res->uc_compcode) {
+       case ROC_IE_OT_UCC_ERR_SA_OVERFLOW:
+               desc.subtype = RTE_ETH_EVENT_IPSEC_ESN_OVERFLOW;
+               break;
+       default:
+               plt_warn("Outbound error, mbuf %p, sa_index %u, "
+                        "compcode %x uc %x", mbuf, sess_priv.sa_idx,
+                        res->compcode, res->uc_compcode);
+               desc.subtype = RTE_ETH_EVENT_IPSEC_UNKNOWN;
+               break;
+       }
+
+       desc.metadata = (uint64_t)priv->userdata;
+       rte_eth_dev_callback_process(eth_dev, RTE_ETH_EVENT_IPSEC, &desc);
+       rte_pktmbuf_free(mbuf);
+}
+
+static int
+cn10k_eth_sec_session_create(void *device,
+                            struct rte_security_session_conf *conf,
+                            struct rte_security_session *sess,
+                            struct rte_mempool *mempool)
+{
+       struct rte_eth_dev *eth_dev = (struct rte_eth_dev *)device;
+       struct cnxk_eth_dev *dev = cnxk_eth_pmd_priv(eth_dev);
+       struct rte_security_ipsec_xform *ipsec;
+       struct cn10k_sec_sess_priv sess_priv;
+       struct rte_crypto_sym_xform *crypto;
+       struct cnxk_eth_sec_sess *eth_sec;
+       bool inbound, inl_dev;
+       int rc = 0;
+
+       if (conf->action_type != RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL)
+               return -ENOTSUP;
+
+       if (conf->protocol != RTE_SECURITY_PROTOCOL_IPSEC)
+               return -ENOTSUP;
+
+       if (rte_security_dynfield_register() < 0)
+               return -ENOTSUP;
+
+       if (rte_eal_process_type() == RTE_PROC_PRIMARY)
+               roc_nix_inl_cb_register(cn10k_eth_sec_sso_work_cb, NULL);
+
+       ipsec = &conf->ipsec;
+       crypto = conf->crypto_xform;
+       inbound = !!(ipsec->direction == RTE_SECURITY_IPSEC_SA_DIR_INGRESS);
+       inl_dev = !!dev->inb.inl_dev;
+
+       /* Search if a session already exits */
+       if (cnxk_eth_sec_sess_get_by_spi(dev, ipsec->spi, inbound)) {
+               plt_err("%s SA with SPI %u already in use",
+                       inbound ? "Inbound" : "Outbound", ipsec->spi);
+               return -EEXIST;
+       }
+
+       if (rte_mempool_get(mempool, (void **)&eth_sec)) {
+               plt_err("Could not allocate security session private data");
+               return -ENOMEM;
+       }
+
+       memset(eth_sec, 0, sizeof(struct cnxk_eth_sec_sess));
+       sess_priv.u64 = 0;
+
+       /* Acquire lock on inline dev for inbound */
+       if (inbound && inl_dev)
+               roc_nix_inl_dev_lock();
+
+       if (inbound) {
+               struct cn10k_inb_priv_data *inb_priv;
+               struct roc_ot_ipsec_inb_sa *inb_sa;
+               uintptr_t sa;
+
+               PLT_STATIC_ASSERT(sizeof(struct cn10k_inb_priv_data) <
+                                 ROC_NIX_INL_OT_IPSEC_INB_SW_RSVD);
+
+               /* Get Inbound SA from NIX_RX_IPSEC_SA_BASE */
+               sa = roc_nix_inl_inb_sa_get(&dev->nix, inl_dev, ipsec->spi);
+               if (!sa && dev->inb.inl_dev) {
+                       plt_err("Failed to create ingress sa, inline dev "
+                               "not found or spi not in range");
+                       rc = -ENOTSUP;
+                       goto mempool_put;
+               } else if (!sa) {
+                       plt_err("Failed to create ingress sa");
+                       rc = -EFAULT;
+                       goto mempool_put;
+               }
+
+               inb_sa = (struct roc_ot_ipsec_inb_sa *)sa;
+
+               /* Check if SA is already in use */
+               if (inb_sa->w2.s.valid) {
+                       plt_err("Inbound SA with SPI %u already in use",
+                               ipsec->spi);
+                       rc = -EBUSY;
+                       goto mempool_put;
+               }
+
+               memset(inb_sa, 0, sizeof(struct roc_ot_ipsec_inb_sa));
+
+               /* Fill inbound sa params */
+               rc = cnxk_ot_ipsec_inb_sa_fill(inb_sa, ipsec, crypto);
+               if (rc) {
+                       plt_err("Failed to init inbound sa, rc=%d", rc);
+                       goto mempool_put;
+               }
+
+               inb_priv = roc_nix_inl_ot_ipsec_inb_sa_sw_rsvd(inb_sa);
+               /* Back pointer to get eth_sec */
+               inb_priv->eth_sec = eth_sec;
+               /* Save userdata in inb private area */
+               inb_priv->userdata = conf->userdata;
+
+               /* Save SA index/SPI in cookie for now */
+               inb_sa->w1.s.cookie = rte_cpu_to_be_32(ipsec->spi);
+
+               /* Prepare session priv */
+               sess_priv.inb_sa = 1;
+               sess_priv.sa_idx = ipsec->spi;
+
+               /* Pointer from eth_sec -> inb_sa */
+               eth_sec->sa = inb_sa;
+               eth_sec->sess = sess;
+               eth_sec->sa_idx = ipsec->spi;
+               eth_sec->spi = ipsec->spi;
+               eth_sec->inl_dev = !!dev->inb.inl_dev;
+               eth_sec->inb = true;
+
+               TAILQ_INSERT_TAIL(&dev->inb.list, eth_sec, entry);
+               dev->inb.nb_sess++;
+       } else {
+               struct cn10k_outb_priv_data *outb_priv;
+               struct roc_ot_ipsec_outb_sa *outb_sa;
+               struct cnxk_ipsec_outb_rlens *rlens;
+               uint64_t sa_base = dev->outb.sa_base;
+               uint32_t sa_idx;
+
+               PLT_STATIC_ASSERT(sizeof(struct cn10k_outb_priv_data) <
+                                 ROC_NIX_INL_OT_IPSEC_OUTB_SW_RSVD);
+
+               /* Alloc an sa index */
+               rc = cnxk_eth_outb_sa_idx_get(dev, &sa_idx);
+               if (rc)
+                       goto mempool_put;
+
+               outb_sa = roc_nix_inl_ot_ipsec_outb_sa(sa_base, sa_idx);
+               outb_priv = roc_nix_inl_ot_ipsec_outb_sa_sw_rsvd(outb_sa);
+               rlens = &outb_priv->rlens;
+
+               memset(outb_sa, 0, sizeof(struct roc_ot_ipsec_outb_sa));
+
+               /* Fill outbound sa params */
+               rc = cnxk_ot_ipsec_outb_sa_fill(outb_sa, ipsec, crypto);
+               if (rc) {
+                       plt_err("Failed to init outbound sa, rc=%d", rc);
+                       rc |= cnxk_eth_outb_sa_idx_put(dev, sa_idx);
+                       goto mempool_put;
+               }
+
+               /* Save userdata */
+               outb_priv->userdata = conf->userdata;
+               outb_priv->sa_idx = sa_idx;
+               outb_priv->eth_sec = eth_sec;
+
+               /* Save rlen info */
+               cnxk_ipsec_outb_rlens_get(rlens, ipsec, crypto);
+
+               /* Prepare session priv */
+               sess_priv.sa_idx = outb_priv->sa_idx;
+               sess_priv.roundup_byte = rlens->roundup_byte;
+               sess_priv.roundup_len = rlens->roundup_len;
+               sess_priv.partial_len = rlens->partial_len;
+
+               /* Pointer from eth_sec -> outb_sa */
+               eth_sec->sa = outb_sa;
+               eth_sec->sess = sess;
+               eth_sec->sa_idx = sa_idx;
+               eth_sec->spi = ipsec->spi;
+
+               TAILQ_INSERT_TAIL(&dev->outb.list, eth_sec, entry);
+               dev->outb.nb_sess++;
+       }
+
+       /* Sync session in context cache */
+       roc_nix_inl_sa_sync(&dev->nix, eth_sec->sa, eth_sec->inb,
+                           ROC_NIX_INL_SA_OP_RELOAD);
+
+       if (inbound && inl_dev)
+               roc_nix_inl_dev_unlock();
+
+       plt_nix_dbg("Created %s session with spi=%u, sa_idx=%u inl_dev=%u",
+                   inbound ? "inbound" : "outbound", eth_sec->spi,
+                   eth_sec->sa_idx, eth_sec->inl_dev);
+       /*
+        * Update fast path info in priv area.
+        */
+       set_sec_session_private_data(sess, (void *)sess_priv.u64);
+
+       return 0;
+mempool_put:
+       if (inbound && inl_dev)
+               roc_nix_inl_dev_unlock();
+       rte_mempool_put(mempool, eth_sec);
+       return rc;
+}
+
+static int
+cn10k_eth_sec_session_destroy(void *device, struct rte_security_session *sess)
+{
+       struct rte_eth_dev *eth_dev = (struct rte_eth_dev *)device;
+       struct cnxk_eth_dev *dev = cnxk_eth_pmd_priv(eth_dev);
+       struct roc_ot_ipsec_inb_sa *inb_sa;
+       struct roc_ot_ipsec_outb_sa *outb_sa;
+       struct cnxk_eth_sec_sess *eth_sec;
+       struct rte_mempool *mp;
+
+       eth_sec = cnxk_eth_sec_sess_get_by_sess(dev, sess);
+       if (!eth_sec)
+               return -ENOENT;
+
+       if (eth_sec->inl_dev)
+               roc_nix_inl_dev_lock();
+
+       if (eth_sec->inb) {
+               inb_sa = eth_sec->sa;
+               /* Disable SA */
+               inb_sa->w2.s.valid = 0;
+
+               TAILQ_REMOVE(&dev->inb.list, eth_sec, entry);
+               dev->inb.nb_sess--;
+       } else {
+               outb_sa = eth_sec->sa;
+               /* Disable SA */
+               outb_sa->w2.s.valid = 0;
+
+               /* Release Outbound SA index */
+               cnxk_eth_outb_sa_idx_put(dev, eth_sec->sa_idx);
+               TAILQ_REMOVE(&dev->outb.list, eth_sec, entry);
+               dev->outb.nb_sess--;
+       }
+
+       /* Sync session in context cache */
+       roc_nix_inl_sa_sync(&dev->nix, eth_sec->sa, eth_sec->inb,
+                           ROC_NIX_INL_SA_OP_RELOAD);
+
+       if (eth_sec->inl_dev)
+               roc_nix_inl_dev_unlock();
+
+       plt_nix_dbg("Destroyed %s session with spi=%u, sa_idx=%u, inl_dev=%u",
+                   eth_sec->inb ? "inbound" : "outbound", eth_sec->spi,
+                   eth_sec->sa_idx, eth_sec->inl_dev);
+
+       /* Put eth_sec object back to pool */
+       mp = rte_mempool_from_obj(eth_sec);
+       set_sec_session_private_data(sess, NULL);
+       rte_mempool_put(mp, eth_sec);
+       return 0;
+}
+
+static const struct rte_security_capability *
+cn10k_eth_sec_capabilities_get(void *device __rte_unused)
+{
+       return cn10k_eth_sec_capabilities;
+}
+
+void
+cn10k_eth_sec_ops_override(void)
+{
+       static int init_once;
+
+       if (init_once)
+               return;
+       init_once = 1;
+
+       /* Update platform specific ops */
+       cnxk_eth_sec_ops.session_create = cn10k_eth_sec_session_create;
+       cnxk_eth_sec_ops.session_destroy = cn10k_eth_sec_session_destroy;
+       cnxk_eth_sec_ops.capabilities_get = cn10k_eth_sec_capabilities_get;
+}
index 68219b8..d27a231 100644 (file)
@@ -16,6 +16,7 @@
 #define NIX_RX_OFFLOAD_MARK_UPDATE_F BIT(3)
 #define NIX_RX_OFFLOAD_TSTAMP_F             BIT(4)
 #define NIX_RX_OFFLOAD_VLAN_STRIP_F  BIT(5)
+#define NIX_RX_OFFLOAD_SECURITY_F    BIT(6)
 
 /* Flags to control cqe_to_mbuf conversion function.
  * Defining it from backwards to denote its been
index f75cae0..8577a7b 100644 (file)
@@ -13,6 +13,7 @@
 #define NIX_TX_OFFLOAD_MBUF_NOFF_F    BIT(3)
 #define NIX_TX_OFFLOAD_TSO_F         BIT(4)
 #define NIX_TX_OFFLOAD_TSTAMP_F              BIT(5)
+#define NIX_TX_OFFLOAD_SECURITY_F     BIT(6)
 
 /* Flags to control xmit_prepare function.
  * Defining it from backwards to denote its been
index c00da62..d86188f 100644 (file)
@@ -38,6 +38,7 @@ sources += files(
 # CN10K
 sources += files(
         'cn10k_ethdev.c',
+        'cn10k_ethdev_sec.c',
         'cn10k_rte_flow.c',
         'cn10k_rx.c',
         'cn10k_rx_mseg.c',
index 74d16e4..5f0e817 100755 (executable)
@@ -49,6 +49,8 @@ cnxk_bphy = {'Class': '08', 'Vendor': '177d', 'Device': 'a089',
              'SVendor': None, 'SDevice': None}
 cnxk_bphy_cgx = {'Class': '08', 'Vendor': '177d', 'Device': 'a059,a060',
                  'SVendor': None, 'SDevice': None}
+cnxk_inl_dev = {'Class': '08', 'Vendor': '177d', 'Device': 'a0f0,a0f1',
+                'SVendor': None, 'SDevice': None}
 
 intel_dlb = {'Class': '0b', 'Vendor': '8086', 'Device': '270b,2710,2714',
              'SVendor': None, 'SDevice': None}
@@ -73,9 +75,9 @@ eventdev_devices = [cavium_sso, cavium_tim, intel_dlb, octeontx2_sso]
 mempool_devices = [cavium_fpa, octeontx2_npa]
 compress_devices = [cavium_zip]
 regex_devices = [octeontx2_ree]
-misc_devices = [cnxk_bphy, cnxk_bphy_cgx, intel_ioat_bdw, intel_ioat_skx, intel_ioat_icx, intel_idxd_spr,
-                intel_ntb_skx, intel_ntb_icx,
-                octeontx2_dma]
+misc_devices = [cnxk_bphy, cnxk_bphy_cgx, cnxk_inl_dev, intel_ioat_bdw,
+               intel_ioat_skx, intel_ioat_icx, intel_idxd_spr, intel_ntb_skx,
+               intel_ntb_icx, octeontx2_dma]
 
 # global dict ethernet devices present. Dictionary indexed by PCI address.
 # Each device within this is itself a dictionary of device properties