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/nics/features.rst b/doc/guides/nics/features.rst
index 1a1dc16c1e..48e3184ad8 100644
--- a/doc/guides/nics/features.rst
+++ b/doc/guides/nics/features.rst
@@ -443,6 +443,24 @@ protocol operations. See security library and PMD documentation for more details
 * **[provides]   rte_security_ops, capabilities_get**:  ``action: RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL``
 
 
+.. _nic_features_rx_inject_doc:
+
+Rx inject
+---------
+
+Supports Rx inject to handle packets that failed inline protocol offload
+processing but need to be handled with same security session. The NIC is
+capable of processing the packet same way as regular inline protocol processed
+packets and would be received on ethdev queue based on rte_flow rules
+configured.
+
+* **[uses]       rte_eth_rxconf,rte_eth_rxmode**: ``offloads:RTE_ETH_RX_OFFLOAD_SEC_RX_INJECT``,
+* **[uses]       mbuf**: ``mbuf.l2_len``.
+* **[implements] rte_security_ctx**: ``inb_pkt_rx_inject``.
+* **[provides]   rte_eth_dev_info**: ``rx_offload_capa,rx_queue_offload_capa:RTE_ETH_RX_OFFLOAD_SEC_RX_INJECT``.
+* **[related]    API**: ``rte_security_inb_pkt_rx_inject``.
+
+
 .. _nic_features_crc_offload:
 
 CRC offload
diff --git a/doc/guides/nics/features/default.ini b/doc/guides/nics/features/default.ini
index 2011e97127..0a1f8dc54b 100644
--- a/doc/guides/nics/features/default.ini
+++ b/doc/guides/nics/features/default.ini
@@ -44,6 +44,7 @@ Rate limitation      =
 Congestion management =
 Inline crypto        =
 Inline protocol      =
+Rx inject            =
 CRC offload          =
 VLAN offload         =
 QinQ offload         =
diff --git a/lib/cryptodev/rte_cryptodev.h b/lib/cryptodev/rte_cryptodev.h
index ba730373fb..c3306b12b4 100644
--- a/lib/cryptodev/rte_cryptodev.h
+++ b/lib/cryptodev/rte_cryptodev.h
@@ -536,6 +536,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/ethdev/rte_ethdev.c b/lib/ethdev/rte_ethdev.c
index 0840d2b594..ae1c7619d1 100644
--- a/lib/ethdev/rte_ethdev.c
+++ b/lib/ethdev/rte_ethdev.c
@@ -106,6 +106,7 @@ static const struct {
 	RTE_RX_OFFLOAD_BIT2STR(OUTER_UDP_CKSUM),
 	RTE_RX_OFFLOAD_BIT2STR(RSS_HASH),
 	RTE_RX_OFFLOAD_BIT2STR(BUFFER_SPLIT),
+	RTE_RX_OFFLOAD_BIT2STR(SEC_RX_INJECT),
 };
 
 #undef RTE_RX_OFFLOAD_BIT2STR
diff --git a/lib/ethdev/rte_ethdev.h b/lib/ethdev/rte_ethdev.h
index 04a2564f22..7054323c86 100644
--- a/lib/ethdev/rte_ethdev.h
+++ b/lib/ethdev/rte_ethdev.h
@@ -1517,6 +1517,8 @@ struct rte_eth_conf {
 #define RTE_ETH_RX_OFFLOAD_OUTER_UDP_CKSUM  RTE_BIT64(18)
 #define RTE_ETH_RX_OFFLOAD_RSS_HASH         RTE_BIT64(19)
 #define RTE_ETH_RX_OFFLOAD_BUFFER_SPLIT     RTE_BIT64(20)
+#define RTE_ETH_RX_OFFLOAD_SEC_RX_INJECT    RTE_BIT64(21)
+#define DEV_RX_OFFLOAD_SEC_RX_INJECT        RTE_ETH_RX_OFFLOAD_SEC_RX_INJECT
 
 #define RTE_ETH_RX_OFFLOAD_CHECKSUM (RTE_ETH_RX_OFFLOAD_IPV4_CKSUM | \
 				 RTE_ETH_RX_OFFLOAD_UDP_CKSUM | \
diff --git a/lib/security/rte_security.h b/lib/security/rte_security.h
index 3b2df526ba..9c1b89cc3a 100644
--- a/lib/security/rte_security.h
+++ b/lib/security/rte_security.h
@@ -55,6 +55,31 @@ enum rte_security_ipsec_tunnel_type {
  */
 #define RTE_SECURITY_IPSEC_TUNNEL_VERIFY_DST_ADDR     0x1
 #define RTE_SECURITY_IPSEC_TUNNEL_VERIFY_SRC_DST_ADDR 0x2
+extern struct rte_security_session **sess;
+
+/**
+ * Perform security processing of the packet and do an Rx inject after the
+ * packet is processed.
+ *
+ * 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 context for crypto/eth devices
@@ -78,6 +103,8 @@ struct rte_security_ctx {
 	/**< Number of MACsec SA attached to this context */
 	uint32_t flags;
 	/**< Flags for security context */
+	security_inb_pkt_rx_inject inb_pkt_rx_inject;
+	/**< Perform security processing and do Rx inject */
 };
 
 #define RTE_SEC_CTX_F_FAST_SET_MDATA 0x00000001
@@ -969,6 +996,66 @@ rte_security_attach_session(struct rte_crypto_op *op,
 	return __rte_security_attach_session(op->sym, sess);
 }
 
+/**
+ * Perform security processing of packets and do Rx inject after processing.
+ *
+ * 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. The ethdev port
+ * on which the packet would be received would be based on rte_flow rules
+ * matching the packet after security processing. Also, since the packet would
+ * be identical to an inline protocol processed packet, eth devices should have
+ * security enabled (`RTE_ETHDEV_RX_SECURITY_F`).
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * @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
+ *				*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.
+ */
+__rte_experimental
+static inline uint16_t
+rte_security_inb_pkt_rx_inject(struct rte_security_ctx *ctx,
+			       struct rte_mbuf **pkts,
+			       struct rte_security_session **sess,
+			       uint16_t nb_pkts)
+{
+#ifdef RTE_DEBUG
+	RTE_PTR_OR_ERR_RET(ctx, 0);
+	RTE_PTR_OR_ERR_RET(ctx->ops, 0);
+	RTE_FUNC_PTR_OR_ERR_RET(ctx->inb_pkt_rx_inject, 0);
+#endif
+	return ctx->inb_pkt_rx_inject(ctx->device, pkts, sess, nb_pkts);
+}
+
+
 struct rte_security_macsec_secy_stats {
 	uint64_t ctl_pkt_bcast_cnt;
 	uint64_t ctl_pkt_mcast_cnt;
diff --git a/lib/security/version.map b/lib/security/version.map
index b2097a969d..99d43dbeef 100644
--- a/lib/security/version.map
+++ b/lib/security/version.map
@@ -15,6 +15,7 @@ EXPERIMENTAL {
 
 	__rte_security_set_pkt_metadata;
 	rte_security_dynfield_offset;
+	rte_security_inb_pkt_rx_inject;
 	rte_security_macsec_sa_create;
 	rte_security_macsec_sa_destroy;
 	rte_security_macsec_sa_stats_get;
