diff --git a/doc/guides/cryptodevs/features/default.ini b/doc/guides/cryptodevs/features/default.ini
index 6f637fa7e2..f411d4bab7 100644
--- a/doc/guides/cryptodevs/features/default.ini
+++ b/doc/guides/cryptodevs/features/default.ini
@@ -34,6 +34,7 @@ Sym raw data path API  =
 Cipher multiple data units =
 Cipher wrapped key     =
 Inner checksum         =
+Rx inject              =
 
 ;
 ; Supported crypto algorithms of a default crypto driver.
diff --git a/doc/guides/rel_notes/release_23_11.rst b/doc/guides/rel_notes/release_23_11.rst
index be51f00dbf..6853c907c9 100644
--- a/doc/guides/rel_notes/release_23_11.rst
+++ b/doc/guides/rel_notes/release_23_11.rst
@@ -107,6 +107,25 @@ New Features
   enhancements to ``rte_crypto_op`` fields to handle all datapath requirements
   of TLS and DTLS. The support is added for TLS 1.2, TLS 1.3 and DTLS 1.2.
 
+* **Added support for rte_security Rx inject API.**
+
+  Added Rx inject API to allow applications to submit packets for protocol
+  offload and have them injected back to ethdev Rx so that further ethdev Rx
+  actions (IP reassembly, packet parsing and flow lookups) can happen based on
+  inner packet.
+
+  The API when implemented by an ethdev, may be used to process packets that the
+  application wants to process with inline protocol offload enabled rte_security
+  session. These can be packets that are received from other non-inline capable
+  ethdevs or can be packets that failed inline protocol offload (such as
+  receiving fragmented ESP packets in case of inline IPsec offload).
+
+  The API when implemented by a cryptodev, can be used for injecting packets to
+  ethdev Rx after IPsec processing and take advantage of ethdev Rx processing
+  for the inner packet. The API helps application to avail ethdev Rx actions
+  based on inner packet while working with rte_security sessions which cannot
+  be accelerated in inline protocol offload mode.
+
 * **Updated ipsec_mb crypto driver.**
 
   Added support for digest encrypted to AESNI_MB asynchronous crypto driver.
diff --git a/lib/cryptodev/rte_cryptodev.h b/lib/cryptodev/rte_cryptodev.h
index 6c8f532797..be0698ce9f 100644
--- a/lib/cryptodev/rte_cryptodev.h
+++ b/lib/cryptodev/rte_cryptodev.h
@@ -559,6 +559,8 @@ rte_cryptodev_asym_get_xform_string(enum rte_crypto_asym_xform_type xform_enum);
 /**< Support wrapped key in cipher xform  */
 #define RTE_CRYPTODEV_FF_SECURITY_INNER_CSUM		(1ULL << 27)
 /**< Support inner checksum computation/verification */
+#define RTE_CRYPTODEV_FF_SECURITY_RX_INJECT		(1ULL << 28)
+/**< Support Rx injection after security processing */
 
 /**
  * Get the name of a crypto device feature flag
diff --git a/lib/security/rte_security.c b/lib/security/rte_security.c
index 04872ec1a0..b082a29029 100644
--- a/lib/security/rte_security.c
+++ b/lib/security/rte_security.c
@@ -325,6 +325,28 @@ rte_security_capability_get(void *ctx, struct rte_security_capability_idx *idx)
 	return NULL;
 }
 
+int
+rte_security_rx_inject_configure(void *ctx, uint16_t port_id, bool enable)
+{
+	struct rte_security_ctx *instance = ctx;
+
+	RTE_PTR_OR_ERR_RET(instance, -EINVAL);
+	RTE_PTR_OR_ERR_RET(instance->ops, -ENOTSUP);
+	RTE_PTR_OR_ERR_RET(instance->ops->rx_inject_configure, -ENOTSUP);
+
+	return instance->ops->rx_inject_configure(instance->device, port_id, enable);
+}
+
+uint16_t
+rte_security_inb_pkt_rx_inject(void *ctx, struct rte_mbuf **pkts, void **sess,
+			       uint16_t nb_pkts)
+{
+	struct rte_security_ctx *instance = ctx;
+
+	return instance->ops->inb_pkt_rx_inject(instance->device, pkts,
+						(struct rte_security_session **)sess, nb_pkts);
+}
+
 static int
 security_handle_cryptodev_list(const char *cmd __rte_unused,
 			       const char *params __rte_unused,
diff --git a/lib/security/rte_security.h b/lib/security/rte_security.h
index 8279bed013..181aa28f5e 100644
--- a/lib/security/rte_security.h
+++ b/lib/security/rte_security.h
@@ -1455,6 +1455,91 @@ const struct rte_security_capability *
 rte_security_capability_get(void *instance,
 			    struct rte_security_capability_idx *idx);
 
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * Configure security device to inject packets to an ethdev port.
+ *
+ * This API must be called only when both security device and the ethdev is in
+ * stopped state. The security device need to be configured before any packets
+ * are submitted to ``rte_security_inb_pkt_rx_inject`` API.
+ *
+ * @param	ctx		Security ctx
+ * @param	port_id		Port identifier of the ethernet device to which
+ *				packets need to be injected.
+ * @param	enable		Flag to enable and disable connection between a
+ *				security device and an ethdev port.
+ * @return
+ *   - 0 if successful.
+ *   - -EINVAL if context NULL or port_id is invalid.
+ *   - -EBUSY if devices are not in stopped state.
+ *   - -ENOTSUP if security device does not support injecting to the ethdev
+ *      port.
+ *
+ * @see rte_security_inb_pkt_rx_inject
+ */
+__rte_experimental
+int
+rte_security_rx_inject_configure(void *ctx, uint16_t port_id, bool enable);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * Perform security processing of packets and inject the processed packet to
+ * ethdev Rx.
+ *
+ * Rx inject would behave similarly to ethdev loopback but with the additional
+ * security processing. In case of ethdev loopback, application would be
+ * submitting packets to ethdev Tx queues and would be received as is from
+ * ethdev Rx queues. With Rx inject, packets would be received after security
+ * processing from ethdev Rx queues.
+ *
+ * With inline protocol offload capable ethdevs, Rx injection can be used to
+ * handle packets which failed the regular security Rx path. This can be due to
+ * cases such as outer fragmentation, in which case applications can reassemble
+ * the fragments and then subsequently submit for inbound processing and Rx
+ * injection, so that packets are received as regular security processed
+ * packets.
+ *
+ * With lookaside protocol offload capable cryptodevs, Rx injection can be used
+ * to perform packet parsing after security processing. This would allow for
+ * re-classification after security protocol processing is done (ie, inner
+ * packet parsing). The ethdev queue on which the packet would be received would
+ * be based on rte_flow rules matching the packet after security processing.
+ *
+ * The security device which is injecting packets to ethdev Rx need to be
+ * configured using ``rte_security_rx_inject_configure`` with enable flag set
+ * to `true` before any packets are submitted.
+ *
+ * If `hash.fdir.h` field is set in mbuf, it would be treated as the value for
+ * `MARK` pattern for the subsequent rte_flow parsing. The packet would appear
+ * as if it is received from `port` field in mbuf.
+ *
+ * Since the packet would be received back from ethdev Rx queues, it is expected
+ * that application retains/adds L2 header with the mbuf field 'l2_len'
+ * reflecting the size of L2 header in the packet.
+ *
+ * @param	ctx		Security ctx
+ * @param	pkts		The address of an array of *nb_pkts* pointers to
+ *				*rte_mbuf* structures which contain the packets.
+ * @param	sess		The address of an array of *nb_pkts* pointers to
+ *				security sessions corresponding to each packet.
+ * @param	nb_pkts		The maximum number of packets to process.
+ *
+ * @return
+ *   The number of packets successfully injected to ethdev Rx. The return
+ *   value can be less than the value of the *nb_pkts* parameter when the
+ *   PMD internal queues have been filled up.
+ *
+ * @see rte_security_rx_inject_configure
+ */
+__rte_experimental
+uint16_t
+rte_security_inb_pkt_rx_inject(void *ctx, struct rte_mbuf **pkts, void **sess,
+			       uint16_t nb_pkts);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/security/rte_security_driver.h b/lib/security/rte_security_driver.h
index e5e1c4cfe8..62664dacdb 100644
--- a/lib/security/rte_security_driver.h
+++ b/lib/security/rte_security_driver.h
@@ -257,6 +257,46 @@ typedef int (*security_set_pkt_metadata_t)(void *device,
 typedef const struct rte_security_capability *(*security_capabilities_get_t)(
 		void *device);
 
+/**
+ * Configure security device to inject packets to an ethdev port.
+ *
+ * @param	device		Crypto/eth device pointer
+ * @param	port_id		Port identifier of the ethernet device to which packets need to be
+ *				injected.
+ * @param	enable		Flag to enable and disable connection between a security device and
+ *				an ethdev port.
+ * @return
+ *   - 0 if successful.
+ *   - -EINVAL if context NULL or port_id is invalid.
+ *   - -EBUSY if devices are not in stopped state.
+ *   - -ENOTSUP if security device does not support injecting to the ethdev port.
+ */
+typedef int (*security_rx_inject_configure)(void *device, uint16_t port_id, bool enable);
+
+/**
+ * Perform security processing of packets and inject the processed packet to
+ * ethdev Rx.
+ *
+ * Rx inject would behave similarly to ethdev loopback but with the additional
+ * security processing.
+ *
+ * @param	device		Crypto/eth device pointer
+ * @param	pkts		The address of an array of *nb_pkts* pointers to
+ *				*rte_mbuf* structures which contain the packets.
+ * @param	sess		The address of an array of *nb_pkts* pointers to
+ *				*rte_security_session* structures corresponding
+ *				to each packet.
+ * @param	nb_pkts		The maximum number of packets to process.
+ *
+ * @return
+ *   The number of packets successfully injected to ethdev Rx. The return
+ *   value can be less than the value of the *nb_pkts* parameter when the
+ *   PMD internal queues have been filled up.
+ */
+typedef uint16_t (*security_inb_pkt_rx_inject)(void *device,
+		struct rte_mbuf **pkts, struct rte_security_session **sess,
+		uint16_t nb_pkts);
+
 /** Security operations function pointer table */
 struct rte_security_ops {
 	security_session_create_t session_create;
@@ -285,6 +325,10 @@ struct rte_security_ops {
 	/**< Get MACsec SC statistics. */
 	security_macsec_sa_stats_get_t macsec_sa_stats_get;
 	/**< Get MACsec SA statistics. */
+	security_rx_inject_configure rx_inject_configure;
+	/**< Rx inject configure. */
+	security_inb_pkt_rx_inject inb_pkt_rx_inject;
+	/**< Perform security processing and do Rx inject. */
 };
 
 #ifdef __cplusplus
diff --git a/lib/security/version.map b/lib/security/version.map
index 86f976a302..e07fca33a1 100644
--- a/lib/security/version.map
+++ b/lib/security/version.map
@@ -24,6 +24,9 @@ EXPERIMENTAL {
 	rte_security_session_stats_get;
 	rte_security_session_update;
 	rte_security_oop_dynfield_offset;
+
+	rte_security_rx_inject_configure;
+	rte_security_inb_pkt_rx_inject;
 };
 
 INTERNAL {
