diff --git a/doc/guides/cryptodevs/octeontx2.rst b/doc/guides/cryptodevs/octeontx2.rst
index 0a38b8662e..170f03dd0f 100644
--- a/doc/guides/cryptodevs/octeontx2.rst
+++ b/doc/guides/cryptodevs/octeontx2.rst
@@ -175,4 +175,6 @@ Features supported
 * IPv6
 * ESP
 * Tunnel mode
+* ESN
+* Anti-replay
 * AES-128/192/256-GCM
diff --git a/doc/guides/rel_notes/release_21_02.rst b/doc/guides/rel_notes/release_21_02.rst
index 638f98168b..d9ca17e83c 100644
--- a/doc/guides/rel_notes/release_21_02.rst
+++ b/doc/guides/rel_notes/release_21_02.rst
@@ -55,6 +55,11 @@ New Features
      Also, make sure to start the actual text at the margin.
      =======================================================
 
+* **Updated the OCTEON TX2 crypto PMD.**
+
+  * Updated the OCTEON TX2 crypto PMD lookaside protocol offload for IPsec with
+    ESN and anti-replay support.
+
 
 Removed Items
 -------------
diff --git a/drivers/crypto/octeontx2/otx2_cryptodev_ops.c b/drivers/crypto/octeontx2/otx2_cryptodev_ops.c
index 5f2ccc0872..16aa7f4a0a 100644
--- a/drivers/crypto/octeontx2/otx2_cryptodev_ops.c
+++ b/drivers/crypto/octeontx2/otx2_cryptodev_ops.c
@@ -14,6 +14,7 @@
 #include "otx2_cryptodev_mbox.h"
 #include "otx2_cryptodev_ops.h"
 #include "otx2_cryptodev_ops_helper.h"
+#include "otx2_ipsec_anti_replay.h"
 #include "otx2_ipsec_po_ops.h"
 #include "otx2_mbox.h"
 #include "otx2_sec_idev.h"
@@ -650,21 +651,55 @@ static __rte_always_inline int __rte_hot
 otx2_cpt_enqueue_sec(struct otx2_cpt_qp *qp, struct rte_crypto_op *op,
 		     struct pending_queue *pend_q)
 {
+	uint32_t winsz, esn_low = 0, esn_hi = 0, seql = 0, seqh = 0;
+	struct rte_mbuf *m_src = op->sym->m_src;
 	struct otx2_sec_session_ipsec_lp *sess;
 	struct otx2_ipsec_po_sa_ctl *ctl_wrd;
+	struct otx2_ipsec_po_in_sa *sa;
 	struct otx2_sec_session *priv;
 	struct cpt_request_info *req;
+	uint64_t seq_in_sa, seq = 0;
+	uint8_t esn;
 	int ret;
 
 	priv = get_sec_session_private_data(op->sym->sec_session);
 	sess = &priv->ipsec.lp;
+	sa = &sess->in_sa;
 
-	ctl_wrd = &sess->in_sa.ctl;
+	ctl_wrd = &sa->ctl;
+	esn = ctl_wrd->esn_en;
+	winsz = sa->replay_win_sz;
 
 	if (ctl_wrd->direction == OTX2_IPSEC_PO_SA_DIRECTION_OUTBOUND)
 		ret = process_outb_sa(op, sess, &qp->meta_info, (void **)&req);
-	else
+	else {
+		if (winsz) {
+			esn_low = rte_be_to_cpu_32(sa->esn_low);
+			esn_hi = rte_be_to_cpu_32(sa->esn_hi);
+			seql = *rte_pktmbuf_mtod_offset(m_src, uint32_t *,
+				sizeof(struct rte_ipv4_hdr) + 4);
+			seql = rte_be_to_cpu_32(seql);
+
+			if (!esn)
+				seq = (uint64_t)seql;
+			else {
+				seqh = anti_replay_get_seqh(winsz, seql, esn_hi,
+						esn_low);
+				seq = ((uint64_t)seqh << 32) | seql;
+			}
+
+			if (unlikely(seq == 0))
+				return IPSEC_ANTI_REPLAY_FAILED;
+
+			ret = anti_replay_check(sa->replay, seq, winsz);
+			if (unlikely(ret)) {
+				otx2_err("Anti replay check failed");
+				return IPSEC_ANTI_REPLAY_FAILED;
+			}
+		}
+
 		ret = process_inb_sa(op, sess, &qp->meta_info, (void **)&req);
+	}
 
 	if (unlikely(ret)) {
 		otx2_err("Crypto req : op %p, ret 0x%x", op, ret);
@@ -673,6 +708,14 @@ otx2_cpt_enqueue_sec(struct otx2_cpt_qp *qp, struct rte_crypto_op *op,
 
 	ret = otx2_cpt_enqueue_req(qp, pend_q, req, sess->cpt_inst_w7);
 
+	if (winsz && esn) {
+		seq_in_sa = ((uint64_t)esn_hi << 32) | esn_low;
+		if (seq > seq_in_sa) {
+			sa->esn_low = rte_cpu_to_be_32(seql);
+			sa->esn_hi = rte_cpu_to_be_32(seqh);
+		}
+	}
+
 	return ret;
 }
 
diff --git a/drivers/crypto/octeontx2/otx2_cryptodev_sec.c b/drivers/crypto/octeontx2/otx2_cryptodev_sec.c
index bad9c5ca9f..1f5645f2f1 100644
--- a/drivers/crypto/octeontx2/otx2_cryptodev_sec.c
+++ b/drivers/crypto/octeontx2/otx2_cryptodev_sec.c
@@ -213,6 +213,7 @@ crypto_sec_ipsec_outb_session_create(struct rte_cryptodev *crypto_dev,
 	int ret;
 
 	sess = get_sec_session_private_data(sec_sess);
+	sess->ipsec.dir = RTE_SECURITY_IPSEC_SA_DIR_EGRESS;
 	lp = &sess->ipsec.lp;
 
 	sa = &lp->out_sa;
@@ -351,6 +352,7 @@ crypto_sec_ipsec_inb_session_create(struct rte_cryptodev *crypto_dev,
 	int ret;
 
 	sess = get_sec_session_private_data(sec_sess);
+	sess->ipsec.dir = RTE_SECURITY_IPSEC_SA_DIR_INGRESS;
 	lp = &sess->ipsec.lp;
 
 	sa = &lp->in_sa;
@@ -362,6 +364,7 @@ crypto_sec_ipsec_inb_session_create(struct rte_cryptodev *crypto_dev,
 	}
 
 	memset(sa, 0, sizeof(struct otx2_ipsec_po_in_sa));
+	sa->replay_win_sz = ipsec->replay_win_sz;
 
 	ret = ipsec_po_sa_ctl_set(ipsec, crypto_xform, ctl);
 	if (ret)
@@ -414,6 +417,24 @@ crypto_sec_ipsec_inb_session_create(struct rte_cryptodev *crypto_dev,
 	set_session_misc_attributes(lp, crypto_xform,
 				    auth_xform, cipher_xform);
 
+	if (sa->replay_win_sz) {
+		if (sa->replay_win_sz > OTX2_IPSEC_MAX_REPLAY_WIN_SZ) {
+			otx2_err("Replay window size is not supported");
+			return -ENOTSUP;
+		}
+		sa->replay = rte_zmalloc(NULL, sizeof(struct otx2_ipsec_replay),
+				0);
+		if (sa->replay == NULL)
+			return -ENOMEM;
+
+		/* Set window bottom to 1, base and top to size of window */
+		sa->replay->winb = 1;
+		sa->replay->wint = sa->replay_win_sz;
+		sa->replay->base = sa->replay_win_sz;
+		sa->esn_low = 0;
+		sa->esn_hi = 0;
+	}
+
 	return otx2_cpt_enq_sa_write(lp, crypto_dev->data->queue_pairs[0],
 				     OTX2_IPSEC_PO_WRITE_IPSEC_INB);
 }
diff --git a/drivers/crypto/octeontx2/otx2_ipsec_anti_replay.h b/drivers/crypto/octeontx2/otx2_ipsec_anti_replay.h
index d599692a75..b2b1f77284 100644
--- a/drivers/crypto/octeontx2/otx2_ipsec_anti_replay.h
+++ b/drivers/crypto/octeontx2/otx2_ipsec_anti_replay.h
@@ -204,4 +204,25 @@ cpt_ipsec_ip_antireplay_check(struct otx2_ipsec_fp_in_sa *sa, char *data)
 
 	return ret;
 }
+
+static inline uint32_t
+anti_replay_get_seqh(uint32_t winsz, uint32_t seql,
+			uint32_t esn_hi, uint32_t esn_low)
+{
+	uint32_t win_low = esn_low - winsz + 1;
+
+	if (esn_low > winsz - 1) {
+		/* Window is in one sequence number subspace */
+		if (seql > win_low)
+			return esn_hi;
+		else
+			return esn_hi + 1;
+	} else {
+		/* Window is split across two sequence number subspaces */
+		if (seql > win_low)
+			return esn_hi - 1;
+		else
+			return esn_hi;
+	}
+}
 #endif /* __OTX2_IPSEC_ANTI_REPLAY_H__ */
diff --git a/drivers/crypto/octeontx2/otx2_ipsec_po.h b/drivers/crypto/octeontx2/otx2_ipsec_po.h
index da24f6a5d4..6d25e29734 100644
--- a/drivers/crypto/octeontx2/otx2_ipsec_po.h
+++ b/drivers/crypto/octeontx2/otx2_ipsec_po.h
@@ -161,6 +161,11 @@ struct otx2_ipsec_po_in_sa {
 		uint8_t hmac_key[48];
 		struct otx2_ipsec_po_traffic_selector selector;
 	} aes_gcm;
+	union {
+		struct otx2_ipsec_replay *replay;
+		uint64_t replay64;
+	};
+	uint32_t replay_win_sz;
 };
 
 struct otx2_ipsec_po_ip_template {
diff --git a/drivers/crypto/octeontx2/otx2_ipsec_po_ops.h b/drivers/crypto/octeontx2/otx2_ipsec_po_ops.h
index bc702d5c79..c0c936141d 100644
--- a/drivers/crypto/octeontx2/otx2_ipsec_po_ops.h
+++ b/drivers/crypto/octeontx2/otx2_ipsec_po_ops.h
@@ -124,6 +124,8 @@ process_outb_sa(struct rte_crypto_op *cop,
 	req->ist.ei1 = rte_pktmbuf_iova(m_src);
 	req->ist.ei2 = req->ist.ei1;
 
+	sa->esn_hi = sess->seq_hi;
+
 	hdr->seq = rte_cpu_to_be_32(sess->seq_lo);
 	hdr->ip_id = rte_cpu_to_be_32(sess->ip_id);
 
