diff --git a/control/descriptor.h b/control/descriptor.h
index 38153b6b2bc444155315d249139236a827a2b1de..d3d65c20c20fed8f9836c8a10aaf5a02572b3ca6 100644
--- a/control/descriptor.h
+++ b/control/descriptor.h
@@ -20,7 +20,7 @@
  * @author Raphael Boucherie
  * @author Samuel Thibault
  * @author Lionel Eyraud-Dubois
- * @date 2023-07-05
+ * @date 2023-08-22
  *
  */
 #ifndef _chameleon_descriptor_h_
@@ -76,6 +76,9 @@ CHAM_desc_t* chameleon_desc_submatrix( CHAM_desc_t *descA, int i, int j, int m,
 void         chameleon_desc_destroy  ( CHAM_desc_t *desc );
 int          chameleon_desc_check    ( const CHAM_desc_t *desc );
 
+int chameleon_ipiv_init( CHAM_ipiv_t *ipiv, const CHAM_desc_t *desc, void *data );
+void chameleon_ipiv_destroy( CHAM_ipiv_t *ipiv );
+
 /**
  *  Internal function to return address of block (m,n) with m,n = block indices
  */
diff --git a/control/descriptor_ipiv.c b/control/descriptor_ipiv.c
new file mode 100644
index 0000000000000000000000000000000000000000..54c9fec4068dfdf0c05ae9b18262d2e179c3995b
--- /dev/null
+++ b/control/descriptor_ipiv.c
@@ -0,0 +1,245 @@
+/**
+ *
+ * @file descriptor_ipiv.c
+ *
+ * @copyright 2022-2023 Bordeaux INP, CNRS (LaBRI UMR 5800), Inria,
+ *                      Univ. Bordeaux. All rights reserved.
+ *
+ ***
+ *
+ * @brief Chameleon descriptors routines
+ *
+ * @version 1.3.0
+ * @author Mathieu Faverge
+ * @author Matthieu Kuhn
+ * @date 2023-08-22
+ *
+ ***
+ *
+ * @defgroup Descriptor
+ * @brief Group descriptor routines exposed to users to manipulate IPIV data structures
+ *
+ */
+#define _GNU_SOURCE 1
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+#include "control/common.h"
+#include "control/descriptor.h"
+#include "chameleon/runtime.h"
+
+/**
+ ******************************************************************************
+ *
+ * @ingroup Descriptor
+ *
+ * @brief Internal function to create tiled descriptor associated to a pivot array.
+ *
+ ******************************************************************************
+ *
+ * @param[in,out] ipiv
+ *          The pointer to the ipiv descriptor to initialize.
+ *
+ * @param[in] desc
+ *          The tile descriptor for which an associated ipiv descriptor must be generated.
+ *
+ * @param[in] data
+ *          The pointer to the original vector where to store the pivot values.
+ *
+ ******************************************************************************
+ *
+ * @return CHAMELEON_SUCCESS on success, CHAMELEON_ERR_NOT_INITIALIZED otherwise.
+ *
+ */
+int chameleon_ipiv_init( CHAM_ipiv_t *ipiv, const CHAM_desc_t *desc, void *data )
+{
+    CHAM_context_t *chamctxt;
+    int rc = CHAMELEON_SUCCESS;
+
+    memset( ipiv, 0, sizeof(CHAM_ipiv_t) );
+
+    chamctxt = chameleon_context_self();
+    if (chamctxt == NULL) {
+        chameleon_error("CHAMELEON_Desc_Create", "CHAMELEON not initialized");
+        return CHAMELEON_ERR_NOT_INITIALIZED;
+    }
+
+    ipiv->desc = desc;
+    ipiv->data = data;
+    ipiv->i    = 0;
+    ipiv->m    = chameleon_min( desc->m, desc->n );
+    ipiv->mb   = desc->mb;
+    ipiv->mt   = chameleon_ceil( ipiv->m, ipiv->mb );
+
+    /* Create runtime specific structure like registering data */
+    RUNTIME_ipiv_create( ipiv );
+
+    return rc;
+}
+
+/**
+ ******************************************************************************
+ *
+ * @ingroup Descriptor
+ *
+ * @brief Internal function to destroy a tiled descriptor associated to a pivot array.
+ *
+ ******************************************************************************
+ *
+ * @param[in,out] ipiv
+ *          The pointer to the ipiv descriptor to destroy.
+ *
+ */
+void chameleon_ipiv_destroy( CHAM_ipiv_t *ipiv )
+{
+    RUNTIME_ipiv_destroy( ipiv );
+}
+
+/**
+ *****************************************************************************
+ *
+ * @ingroup Descriptor
+ *
+ * @brief Create a tiled ipiv descriptor associated to a given matrix.
+ *
+ ******************************************************************************
+ *
+ * @param[in,out] ipiv
+ *          The pointer to the ipiv descriptor to initialize.
+ *
+ * @param[in] desc
+ *          The tile descriptor for which an associated ipiv descriptor must be generated.
+ *
+ * @param[in] data
+ *          The pointer to the original vector where to store the pivot values.
+ *
+ ******************************************************************************
+ *
+ * @retval CHAMELEON_SUCCESS on successful exit
+ * @retval CHAMELEON_ERR_NOT_INITIALIZED if failed to initialize the descriptor.
+ * @retval CHAMELEON_ERR_OUT_OF_RESOURCES if failed to allocated some ressources.
+ *
+ */
+int CHAMELEON_Ipiv_Create( CHAM_ipiv_t **ipivptr, const CHAM_desc_t *desc, void *data )
+{
+    CHAM_context_t *chamctxt;
+    CHAM_ipiv_t *ipiv;
+
+    chamctxt = chameleon_context_self();
+    if (chamctxt == NULL) {
+        chameleon_error("CHAMELEON_Ipiv_Create", "CHAMELEON not initialized");
+        return CHAMELEON_ERR_NOT_INITIALIZED;
+    }
+
+    /* Allocate memory and initialize the ipivriptor */
+    ipiv = (CHAM_ipiv_t*)malloc(sizeof(CHAM_ipiv_t));
+    if (ipiv == NULL) {
+        chameleon_error("CHAMELEON_Ipiv_Create", "malloc() failed");
+        return CHAMELEON_ERR_OUT_OF_RESOURCES;
+    }
+
+    chameleon_ipiv_init( ipiv, desc, data );
+
+    *ipivptr = ipiv;
+    return CHAMELEON_SUCCESS;
+}
+
+/**
+ *****************************************************************************
+ *
+ * @ingroup Descriptor
+ *
+ * @brief Destroys an ipiv tile descriptor.
+ *
+ ******************************************************************************
+ *
+ * @param[in] ipivptr
+ *          The Ipiv tile descriptor to destroy.
+ *
+ ******************************************************************************
+ *
+ * @retval CHAMELEON_SUCCESS successful exit
+ *
+ */
+int CHAMELEON_Ipiv_Destroy(CHAM_ipiv_t **ipivptr)
+{
+    CHAM_context_t *chamctxt;
+    CHAM_ipiv_t *ipiv;
+
+    chamctxt = chameleon_context_self();
+    if (chamctxt == NULL) {
+        chameleon_error("CHAMELEON_Ipiv_Destroy", "CHAMELEON not initialized");
+        return CHAMELEON_ERR_NOT_INITIALIZED;
+    }
+
+    if ((ipivptr == NULL) || (*ipivptr == NULL)) {
+        chameleon_error("CHAMELEON_Ipiv_Destroy", "attempting to destroy a NULL descriptor");
+        return CHAMELEON_ERR_UNALLOCATED;
+    }
+
+    ipiv = *ipivptr;
+    chameleon_ipiv_destroy( ipiv );
+    free(ipiv);
+    *ipivptr = NULL;
+    return CHAMELEON_SUCCESS;
+}
+
+ /**
+ *****************************************************************************
+ *
+ * @ingroup Descriptor
+ *
+ * @brief Flushes the data in the sequence when they won't be reused. This calls
+ * cleans up the distributed communication caches, and transfer the data back to
+ * the CPU.
+ *
+ ******************************************************************************
+ *
+ * @param[in] ipiv
+ *          ipiv vector descriptor.
+ *
+ * @param[in] sequence
+ *          The seqeunce in which to submit the calls to flush the data.
+ *
+ ******************************************************************************
+ *
+ * @retval CHAMELEON_SUCCESS successful exit
+ *
+ */
+int CHAMELEON_Ipiv_Flush( const CHAM_ipiv_t        *ipiv,
+                          const RUNTIME_sequence_t *sequence )
+{
+    RUNTIME_ipiv_flush( ipiv, sequence );
+    return CHAMELEON_SUCCESS;
+}
+
+/**
+ *****************************************************************************
+ *
+ * @ingroup Descriptor
+ *
+ * @brief Gathers an IPIV tile descriptor in a single vector on the given root node.
+ *
+ ******************************************************************************
+ *
+ * @param[in] ipivdesc
+ *          the ipiv vector descriptor to gather.
+ *
+ * @param[in] ipiv
+ *          The ipiv vector where to store the result. Allocated vector of size
+ *          ipivdesc->m on root, not referenced on other nodes.
+ *
+ * @param[in] root
+ *          root node on which to gather the data.
+ *
+ ******************************************************************************
+ *
+ * @retval CHAMELEON_SUCCESS successful exit
+ *
+ */
+int CHAMELEON_Ipiv_Gather( CHAM_ipiv_t *ipivdesc, int *ipiv, int root )
+{
+    RUNTIME_ipiv_gather( ipivdesc, ipiv, root );
+    return CHAMELEON_SUCCESS;
+}
diff --git a/include/chameleon.h b/include/chameleon.h
index cce6539fc5cc06e00d3cd887c18bd12f7d570ae1..253767cbb86d28adf7acc00a4b21d3edb935af39 100644
--- a/include/chameleon.h
+++ b/include/chameleon.h
@@ -18,7 +18,7 @@
  * @author Florent Pruvost
  * @author Philippe Virouleau
  * @author Lionel Eyraud-Dubois
- * @date 2023-07-05
+ * @date 2023-08-22
  *
  */
 #ifndef _chameleon_h_
@@ -195,6 +195,13 @@ int  CHAMELEON_Recursive_Desc_Create( CHAM_desc_t **descptr, void *mat, cham_flt
                                       blkaddr_fct_t get_blkaddr, blkldd_fct_t get_blkldd,
                                       blkrankof_fct_t get_rankof, void* get_rankof_arg );
 
+int CHAMELEON_Ipiv_Create ( CHAM_ipiv_t **ipivptr, const CHAM_desc_t *desc, void *data );
+int CHAMELEON_Ipiv_Destroy( CHAM_ipiv_t **ipivptr );
+int CHAMELEON_Ipiv_Flush  ( const CHAM_ipiv_t        *ipiv,
+                            const RUNTIME_sequence_t *sequence );
+int CHAMELEON_Ipiv_Gather( CHAM_ipiv_t *ipivdesc, int *ipiv, int root );
+void CHAMELEON_Ipiv_Print ( const CHAM_ipiv_t *ipiv );
+
 /**
  *
  * @ingroup Control