From: Nithin Dabilpuram Date: Fri, 1 Oct 2021 13:40:11 +0000 (+0530) Subject: net/cnxk: support inline security setup for cn10k X-Git-Url: http://git.droids-corp.org/?a=commitdiff_plain;h=69daa9e5022b82a0daa0f2a96d1a074dbe25f520;p=dpdk.git net/cnxk: support inline security setup for cn10k 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 Acked-by: Jerin Jacob --- diff --git a/doc/guides/nics/cnxk.rst b/doc/guides/nics/cnxk.rst index 90d27dbaa5..b5424376f1 100644 --- a/doc/guides/nics/cnxk.rst +++ b/doc/guides/nics/cnxk.rst @@ -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 ----------------- diff --git a/doc/guides/nics/features/cnxk.ini b/doc/guides/nics/features/cnxk.ini index 5d456257bd..1ced3ee903 100644 --- a/doc/guides/nics/features/cnxk.ini +++ b/doc/guides/nics/features/cnxk.ini @@ -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 diff --git a/doc/guides/nics/features/cnxk_vec.ini b/doc/guides/nics/features/cnxk_vec.ini index abf2b8d705..12ca0a587c 100644 --- a/doc/guides/nics/features/cnxk_vec.ini +++ b/doc/guides/nics/features/cnxk_vec.ini @@ -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 diff --git a/doc/guides/nics/features/cnxk_vf.ini b/doc/guides/nics/features/cnxk_vf.ini index 7b4299f0be..139d9b9892 100644 --- a/doc/guides/nics/features/cnxk_vf.ini +++ b/doc/guides/nics/features/cnxk_vf.ini @@ -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 diff --git a/doc/guides/rel_notes/release_21_11.rst b/doc/guides/rel_notes/release_21_11.rst index 9e10d28298..0f200891c7 100644 --- a/doc/guides/rel_notes/release_21_11.rst +++ b/doc/guides/rel_notes/release_21_11.rst @@ -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.** diff --git a/drivers/event/cnxk/cnxk_eventdev_adptr.c b/drivers/event/cnxk/cnxk_eventdev_adptr.c index baf2f2aa6b..a34efbbfaa 100644 --- a/drivers/event/cnxk/cnxk_eventdev_adptr.c +++ b/drivers/event/cnxk/cnxk_eventdev_adptr.c @@ -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; } diff --git a/drivers/net/cnxk/cn10k_ethdev.c b/drivers/net/cnxk/cn10k_ethdev.c index 7caec6cf14..fa2343c242 100644 --- a/drivers/net/cnxk/cn10k_ethdev.c +++ b/drivers/net/cnxk/cn10k_ethdev.c @@ -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) diff --git a/drivers/net/cnxk/cn10k_ethdev.h b/drivers/net/cnxk/cn10k_ethdev.h index 8b6e0f2b3f..a888364020 100644 --- a/drivers/net/cnxk/cn10k_ethdev.h +++ b/drivers/net/cnxk/cn10k_ethdev.h @@ -5,6 +5,7 @@ #define __CN10K_ETHDEV_H__ #include +#include 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 index 0000000000..3ffd824a21 --- /dev/null +++ b/drivers/net/cnxk/cn10k_ethdev_sec.c @@ -0,0 +1,426 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(C) 2021 Marvell. + */ + +#include +#include +#include +#include + +#include +#include + +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 **)ð_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; +} diff --git a/drivers/net/cnxk/cn10k_rx.h b/drivers/net/cnxk/cn10k_rx.h index 68219b8c19..d27a231819 100644 --- a/drivers/net/cnxk/cn10k_rx.h +++ b/drivers/net/cnxk/cn10k_rx.h @@ -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 diff --git a/drivers/net/cnxk/cn10k_tx.h b/drivers/net/cnxk/cn10k_tx.h index f75cae07ae..8577a7b596 100644 --- a/drivers/net/cnxk/cn10k_tx.h +++ b/drivers/net/cnxk/cn10k_tx.h @@ -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 diff --git a/drivers/net/cnxk/meson.build b/drivers/net/cnxk/meson.build index c00da62881..d86188fed7 100644 --- a/drivers/net/cnxk/meson.build +++ b/drivers/net/cnxk/meson.build @@ -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', diff --git a/usertools/dpdk-devbind.py b/usertools/dpdk-devbind.py index 74d16e4c4b..5f0e817055 100755 --- a/usertools/dpdk-devbind.py +++ b/usertools/dpdk-devbind.py @@ -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