diff --git a/drivers/common/cnxk/roc_nix.h b/drivers/common/cnxk/roc_nix.h
index dbb816d961..7313cc4d36 100644
--- a/drivers/common/cnxk/roc_nix.h
+++ b/drivers/common/cnxk/roc_nix.h
@@ -405,6 +405,7 @@ struct roc_nix {
 	bool io_enabled;
 	bool rx_ptp_ena;
 	uint16_t cints;
+	bool custom_sa_action;
 
 #define ROC_NIX_MEM_SZ (6 * 1024)
 	uint8_t reserved[ROC_NIX_MEM_SZ] __plt_cache_aligned;
diff --git a/drivers/common/cnxk/roc_nix_inl.c b/drivers/common/cnxk/roc_nix_inl.c
index 826c6e99c1..e14f8a1f32 100644
--- a/drivers/common/cnxk/roc_nix_inl.c
+++ b/drivers/common/cnxk/roc_nix_inl.c
@@ -217,6 +217,14 @@ roc_nix_inl_inb_sa_get(struct roc_nix *roc_nix, bool inb_inl_dev, uint32_t spi)
 	if (!sa_base)
 		return 0;
 
+	/* Get SA size */
+	sz = roc_nix_inl_inb_sa_sz(roc_nix, inb_inl_dev);
+	if (!sz)
+		return 0;
+
+	if (roc_nix->custom_sa_action)
+		return (sa_base + (spi * sz));
+
 	/* Check if SPI is in range */
 	mask = roc_nix_inl_inb_spi_range(roc_nix, inb_inl_dev, &min_spi,
 					 &max_spi);
@@ -224,11 +232,6 @@ roc_nix_inl_inb_sa_get(struct roc_nix *roc_nix, bool inb_inl_dev, uint32_t spi)
 		plt_warn("Inbound SA SPI %u not in range (%u..%u)", spi,
 			 min_spi, max_spi);
 
-	/* Get SA size */
-	sz = roc_nix_inl_inb_sa_sz(roc_nix, inb_inl_dev);
-	if (!sz)
-		return 0;
-
 	/* Basic logic of SPI->SA for now */
 	return (sa_base + ((spi & mask) * sz));
 }
diff --git a/drivers/common/cnxk/roc_npc.c b/drivers/common/cnxk/roc_npc.c
index fc88fd58bc..784f63d92a 100644
--- a/drivers/common/cnxk/roc_npc.c
+++ b/drivers/common/cnxk/roc_npc.c
@@ -293,6 +293,48 @@ roc_npc_validate_portid_action(struct roc_npc *roc_npc_src,
 	return 0;
 }
 
+static int
+npc_parse_msns_action(struct roc_npc *roc_npc, const struct roc_npc_action *act,
+		      struct roc_npc_flow *flow, uint8_t *has_msns_action)
+{
+	const struct roc_npc_sec_action *sec_action;
+	union {
+		uint64_t reg;
+		union nix_rx_vtag_action_u act;
+	} vtag_act;
+
+	if (roc_npc->roc_nix->custom_sa_action == 0 ||
+	    roc_model_is_cn9k() == 1 || act->conf == NULL)
+		return 0;
+
+	*has_msns_action = true;
+	sec_action = act->conf;
+
+	vtag_act.reg = 0;
+	vtag_act.act.sa_xor = sec_action->sa_xor;
+	vtag_act.act.sa_hi = sec_action->sa_hi;
+	vtag_act.act.sa_lo = sec_action->sa_lo;
+
+	switch (sec_action->alg) {
+	case ROC_NPC_SEC_ACTION_ALG0:
+		break;
+	case ROC_NPC_SEC_ACTION_ALG1:
+		vtag_act.act.vtag1_valid = false;
+		vtag_act.act.vtag1_lid = ROC_NPC_SEC_ACTION_ALG1;
+		break;
+	case ROC_NPC_SEC_ACTION_ALG2:
+		vtag_act.act.vtag1_valid = false;
+		vtag_act.act.vtag1_lid = ROC_NPC_SEC_ACTION_ALG2;
+		break;
+	default:
+		return -1;
+	}
+
+	flow->vtag_action = vtag_act.reg;
+
+	return 0;
+}
+
 static int
 npc_parse_actions(struct roc_npc *roc_npc, const struct roc_npc_attr *attr,
 		  const struct roc_npc_action actions[],
@@ -305,11 +347,13 @@ npc_parse_actions(struct roc_npc *roc_npc, const struct roc_npc_attr *attr,
 	const struct roc_npc_action_queue *act_q;
 	const struct roc_npc_action_vf *vf_act;
 	bool vlan_insert_action = false;
+	uint8_t has_msns_act = 0;
 	int sel_act, req_act = 0;
 	uint16_t pf_func, vf_id;
 	int errcode = 0;
 	int mark = 0;
 	int rq = 0;
+	int rc = 0;
 
 	/* Initialize actions */
 	flow->ctr_id = NPC_COUNTER_NONE;
@@ -399,6 +443,12 @@ npc_parse_actions(struct roc_npc *roc_npc, const struct roc_npc_attr *attr,
 				rq = 0;
 				pf_func = nix_inl_dev_pffunc_get();
 			}
+			rc = npc_parse_msns_action(roc_npc, actions, flow,
+						   &has_msns_act);
+			if (rc) {
+				errcode = NPC_ERR_ACTION_NOTSUP;
+				goto err_exit;
+			}
 			break;
 		case ROC_NPC_ACTION_TYPE_VLAN_STRIP:
 			req_act |= ROC_NPC_ACTION_TYPE_VLAN_STRIP;
@@ -438,6 +488,14 @@ npc_parse_actions(struct roc_npc *roc_npc, const struct roc_npc_attr *attr,
 		goto err_exit;
 	}
 
+	if (has_msns_act && (vlan_insert_action ||
+			     (req_act & ROC_NPC_ACTION_TYPE_VLAN_STRIP))) {
+		plt_err("Both MSNS and VLAN insert/strip action can't be supported"
+			" together");
+		errcode = NPC_ERR_ACTION_NOTSUP;
+		goto err_exit;
+	}
+
 	/* Both STRIP and INSERT actions are not supported */
 	if (vlan_insert_action && (req_act & ROC_NPC_ACTION_TYPE_VLAN_STRIP)) {
 		errcode = NPC_ERR_ACTION_NOTSUP;
diff --git a/drivers/common/cnxk/roc_npc.h b/drivers/common/cnxk/roc_npc.h
index 6204139396..78cdf3a318 100644
--- a/drivers/common/cnxk/roc_npc.h
+++ b/drivers/common/cnxk/roc_npc.h
@@ -209,6 +209,25 @@ struct roc_npc_action_meter {
 	uint32_t mtr_id; /**< Meter id to be applied. > */
 };
 
+enum roc_npc_sec_action_alg {
+	ROC_NPC_SEC_ACTION_ALG0,
+	ROC_NPC_SEC_ACTION_ALG1,
+	ROC_NPC_SEC_ACTION_ALG2,
+	ROC_NPC_SEC_ACTION_ALG3,
+};
+
+struct roc_npc_sec_action {
+	/* Used as lookup result for ALG3 */
+	uint32_t sa_index;
+	/* When true XOR initial SA_INDEX with SA_HI/SA_LO to get SA_MCAM */
+	bool sa_xor;
+	uint16_t sa_hi, sa_lo;
+	/* Determines alg to be applied post SA_MCAM computation with/without
+	 * XOR
+	 */
+	enum roc_npc_sec_action_alg alg;
+};
+
 struct roc_npc_attr {
 	uint32_t priority;	/**< Rule priority level within group. */
 	uint32_t ingress : 1;	/**< Rule applies to ingress traffic. */
