plugins types FEATURE sort callback in instanceid
diff --git a/src/plugins_types.h b/src/plugins_types.h
index 366a001..09a3b52 100644
--- a/src/plugins_types.h
+++ b/src/plugins_types.h
@@ -953,6 +953,12 @@
         const struct lyd_value *val2);
 
 /**
+ * @brief Implementation of ::lyplg_type_sort_clb for the built-in instance-identifier type.
+ */
+LIBYANG_API_DEF int lyplg_type_sort_instanceid(const struct ly_ctx *ctx, const struct lyd_value *val1,
+        const struct lyd_value *val2);
+
+/**
  * @brief Implementation of ::lyplg_type_print_clb for the built-in instance-identifier type.
  */
 LIBYANG_API_DECL const void *lyplg_type_print_instanceid(const struct ly_ctx *ctx, const struct lyd_value *value,
diff --git a/src/plugins_types/instanceid.c b/src/plugins_types/instanceid.c
index bf23df9..d6fa0a0 100644
--- a/src/plugins_types/instanceid.c
+++ b/src/plugins_types/instanceid.c
@@ -311,6 +311,94 @@
     return LY_SUCCESS;
 }
 
+LIBYANG_API_DEF int
+lyplg_type_sort_instanceid(const struct ly_ctx *ctx, const struct lyd_value *val1, const struct lyd_value *val2)
+{
+    LY_ARRAY_COUNT_TYPE u, v;
+    int cmp;
+
+#define PL_CHECK_RET(RET) \
+        if (RET > 0) { \
+            return 1; \
+        } else if (RET < 0) { \
+            return -1; \
+        }
+
+    if (val1 == val2) {
+        return LY_SUCCESS;
+    } else if (LY_ARRAY_COUNT(val1->target) > LY_ARRAY_COUNT(val2->target)) {
+        return 1;
+    } else if (LY_ARRAY_COUNT(val1->target) < LY_ARRAY_COUNT(val2->target)) {
+        return -1;
+    }
+
+    LY_ARRAY_FOR(val1->target, u) {
+        struct ly_path *s1 = &val1->target[u];
+        struct ly_path *s2 = &val2->target[u];
+
+        if (s1->node != s2->node) {
+            cmp = strcmp(val1->_canonical, val2->_canonical);
+            PL_CHECK_RET(cmp);
+            continue;
+        } else if (s1->predicates) {
+            if (LY_ARRAY_COUNT(s1->predicates) > LY_ARRAY_COUNT(s2->predicates)) {
+                return 1;
+            } else if (LY_ARRAY_COUNT(s1->predicates) < LY_ARRAY_COUNT(s2->predicates)) {
+                return -1;
+            }
+        }
+        LY_ARRAY_FOR(s1->predicates, v) {
+            struct ly_path_predicate *pred1 = &s1->predicates[v];
+            struct ly_path_predicate *pred2 = &s2->predicates[v];
+
+            if (pred1->type > pred2->type) {
+                return 1;
+            } else if (pred1->type < pred2->type) {
+                return -1;
+            }
+
+            switch (pred1->type) {
+            case LY_PATH_PREDTYPE_POSITION:
+                /* position predicate */
+                if (pred1->position > pred2->position) {
+                    return 1;
+                } else if (pred1->position < pred2->position) {
+                    return -1;
+                }
+                break;
+            case LY_PATH_PREDTYPE_LIST:
+                /* key-predicate */
+                if (pred1->key != pred2->key) {
+                    cmp = strcmp(pred1->key->name, pred2->key->name);
+                    PL_CHECK_RET(cmp);
+                } else {
+                    cmp = ((struct lysc_node_leaf *)pred1->key)->type->plugin->sort(ctx, &pred1->value, &pred2->value);
+                    PL_CHECK_RET(cmp);
+                }
+                break;
+            case LY_PATH_PREDTYPE_LEAFLIST:
+                /* leaf-list predicate */
+                cmp = ((struct lysc_node_leaflist *)s1->node)->type->plugin->sort(ctx, &pred1->value, &pred2->value);
+                PL_CHECK_RET(cmp);
+                break;
+            case LY_PATH_PREDTYPE_LIST_VAR:
+                /* key-predicate with a variable */
+                if (pred1->key != pred2->key) {
+                    cmp = strcmp(pred1->key->name, pred2->key->name);
+                    PL_CHECK_RET(cmp);
+                }
+                cmp = strcmp(pred1->variable, pred2->variable);
+                PL_CHECK_RET(cmp);
+                break;
+            }
+        }
+    }
+
+#undef PL_CHECK_RET
+
+    return 0;
+}
+
 LIBYANG_API_DEF const void *
 lyplg_type_print_instanceid(const struct ly_ctx *UNUSED(ctx), const struct lyd_value *value, LY_VALUE_FORMAT format,
         void *prefix_data, ly_bool *dynamic, size_t *value_len)
@@ -386,7 +474,7 @@
         .plugin.store = lyplg_type_store_instanceid,
         .plugin.validate = lyplg_type_validate_instanceid,
         .plugin.compare = lyplg_type_compare_instanceid,
-        .plugin.sort = NULL,
+        .plugin.sort = lyplg_type_sort_instanceid,
         .plugin.print = lyplg_type_print_instanceid,
         .plugin.duplicate = lyplg_type_dup_instanceid,
         .plugin.free = lyplg_type_free_instanceid,
diff --git a/src/plugins_types/instanceid_keys.c b/src/plugins_types/instanceid_keys.c
index 9490344..12d28e5 100644
--- a/src/plugins_types/instanceid_keys.c
+++ b/src/plugins_types/instanceid_keys.c
@@ -243,7 +243,7 @@
         .plugin.store = lyplg_type_store_instanceid_keys,
         .plugin.validate = NULL,
         .plugin.compare = lyplg_type_compare_simple,
-        .plugin.sort = NULL,
+        .plugin.sort = lyplg_type_sort_simple,
         .plugin.print = lyplg_type_print_xpath10,
         .plugin.duplicate = lyplg_type_dup_xpath10,
         .plugin.free = lyplg_type_free_xpath10,
diff --git a/src/plugins_types/node_instanceid.c b/src/plugins_types/node_instanceid.c
index 2fc91a5..21448e3 100644
--- a/src/plugins_types/node_instanceid.c
+++ b/src/plugins_types/node_instanceid.c
@@ -313,7 +313,7 @@
         .plugin.store = lyplg_type_store_node_instanceid,
         .plugin.validate = NULL,
         .plugin.compare = lyplg_type_compare_instanceid,
-        .plugin.sort = NULL,
+        .plugin.sort = lyplg_type_sort_instanceid,
         .plugin.print = lyplg_type_print_node_instanceid,
         .plugin.duplicate = lyplg_type_dup_instanceid,
         .plugin.free = lyplg_type_free_instanceid,
@@ -328,7 +328,7 @@
         .plugin.store = lyplg_type_store_node_instanceid,
         .plugin.validate = NULL,
         .plugin.compare = lyplg_type_compare_instanceid,
-        .plugin.sort = NULL,
+        .plugin.sort = lyplg_type_sort_instanceid,
         .plugin.print = lyplg_type_print_node_instanceid,
         .plugin.duplicate = lyplg_type_dup_instanceid,
         .plugin.free = lyplg_type_free_instanceid,
diff --git a/tests/utests/types/instanceid.c b/tests/utests/types/instanceid.c
index ce5a24e..c181d59 100644
--- a/tests/utests/types/instanceid.c
+++ b/tests/utests/types/instanceid.c
@@ -280,12 +280,109 @@
     TEST_SUCCESS_LYB2("lyb2", "nii", "ll[. = 'some_string']");
 }
 
+static void
+test_plugin_sort(void **state)
+{
+    const char *schema, *p1, *p2;
+    struct lys_module *mod;
+    struct lyplg_type *type = lyplg_type_plugin_find("", NULL, ly_data_type2str[LY_TYPE_INST]);
+    struct lysc_type *lysc_type;
+    struct ly_err_item *err = NULL;
+    struct lyd_value val1 = {0}, val2 = {0};
+    struct lysc_node *ctx_node;
+
+    schema = MODULE_CREATE_YANG("mod",
+            "leaf-list llii { "
+            "  type instance-identifier {"
+            "    require-instance false;"
+            "  }"
+            "}"
+            "container cont {"
+            "  leaf cl {"
+            "    type uint32;"
+            "  }"
+            "}"
+            "leaf l1 {"
+            "  type uint32;"
+            "}"
+            "leaf l2 {"
+            "  type uint32;"
+            "}"
+            "leaf-list ll {"
+            "  type uint32;"
+            "}"
+            "list l2k {"
+            "  key \"k1 k2\";"
+            "  leaf k1 {"
+            "    type uint32;"
+            "  }"
+            "  leaf k2 {"
+            "    type uint32;"
+            "  }"
+            "  leaf d {"
+            "    type uint32;"
+            "  }"
+            "}");
+
+    UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, &mod);
+    lysc_type = ((struct lysc_node_leaf *)mod->compiled->data)->type;
+    ctx_node = mod->compiled->data;
+
+    /* different number of paths -> sort by number of paths */
+    p1 = "/mod:cont/cl";
+    p2 = "/mod:l1";
+    assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, p1, strlen(p1),
+            0, LY_VALUE_JSON, NULL, LYD_VALHINT_STRING, ctx_node, &val1, NULL, &err));
+    assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, p2, strlen(p2),
+            0, LY_VALUE_JSON, NULL, LYD_VALHINT_STRING, ctx_node, &val2, NULL, &err));
+    assert_int_equal(1, type->sort(UTEST_LYCTX, &val1, &val2));
+    assert_int_equal(-1, type->sort(UTEST_LYCTX, &val2, &val1));
+    type->free(UTEST_LYCTX, &val1);
+    type->free(UTEST_LYCTX, &val2);
+
+    /* different lysc nodes */
+    p1 = "/mod:l1";
+    p2 = "/mod:l2";
+    assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, p1, strlen(p1),
+            0, LY_VALUE_JSON, NULL, LYD_VALHINT_STRING, ctx_node, &val1, NULL, &err));
+    assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, p2, strlen(p2),
+            0, LY_VALUE_JSON, NULL, LYD_VALHINT_STRING, ctx_node, &val2, NULL, &err));
+    assert_int_equal(-1, type->sort(UTEST_LYCTX, &val1, &val2));
+    assert_int_equal(1, type->sort(UTEST_LYCTX, &val2, &val1));
+    type->free(UTEST_LYCTX, &val1);
+    type->free(UTEST_LYCTX, &val2);
+
+    /* different values in predicates */
+    p1 = "/mod:l2k[k1='1'][k2='3']";
+    p2 = "/mod:l2k[k1='1'][k2='2']";
+    assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, p1, strlen(p1),
+            0, LY_VALUE_JSON, NULL, LYD_VALHINT_STRING, ctx_node, &val1, NULL, &err));
+    assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, p2, strlen(p2),
+            0, LY_VALUE_JSON, NULL, LYD_VALHINT_STRING, ctx_node, &val2, NULL, &err));
+    assert_int_equal(1, type->sort(UTEST_LYCTX, &val1, &val2));
+    assert_int_equal(-1, type->sort(UTEST_LYCTX, &val2, &val1));
+    type->free(UTEST_LYCTX, &val1);
+    type->free(UTEST_LYCTX, &val2);
+
+    /* equal */
+    p1 = "/mod:ll[.='1']";
+    p2 = "/mod:ll[.='1']";
+    assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, p1, strlen(p1),
+            0, LY_VALUE_JSON, NULL, LYD_VALHINT_STRING, ctx_node, &val1, NULL, &err));
+    assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, p2, strlen(p2),
+            0, LY_VALUE_JSON, NULL, LYD_VALHINT_STRING, ctx_node, &val2, NULL, &err));
+    assert_int_equal(0, type->sort(UTEST_LYCTX, &val1, &val2));
+    type->free(UTEST_LYCTX, &val1);
+    type->free(UTEST_LYCTX, &val2);
+}
+
 int
 main(void)
 {
     const struct CMUnitTest tests[] = {
         UTEST(test_data_xml),
         UTEST(test_plugin_lyb),
+        UTEST(test_plugin_sort),
     };
 
     return cmocka_run_group_tests(tests, NULL, NULL);