plugins types FEATURE sort callback in inet_types
diff --git a/src/plugins_types/ipv4_address.c b/src/plugins_types/ipv4_address.c
index 946968c..b1a0636 100644
--- a/src/plugins_types/ipv4_address.c
+++ b/src/plugins_types/ipv4_address.c
@@ -14,6 +14,7 @@
 
 #define _GNU_SOURCE /* strndup */
 
+#include "plugins_internal.h"
 #include "plugins_types.h"
 
 #ifdef _WIN32
@@ -226,6 +227,35 @@
 }
 
 /**
+ * @brief Implementation of ::lyplg_type_sort_clb for the ipv4-address ietf-inet-types type.
+ */
+static int
+lyplg_type_sort_ipv4_address(const struct ly_ctx *UNUSED(ctx), const struct lyd_value *val1,
+        const struct lyd_value *val2)
+{
+    struct lyd_value_ipv4_address *v1, *v2;
+    int cmp;
+
+    LYD_VALUE_GET(val1, v1);
+    LYD_VALUE_GET(val2, v2);
+
+    cmp = memcmp(&v1->addr, &v2->addr, sizeof v1->addr);
+    if (cmp != 0) {
+        return cmp;
+    }
+
+    if (!v1->zone && v2->zone) {
+        return -1;
+    } else if (v1->zone && !v2->zone) {
+        return 1;
+    } else if (v1->zone && v2->zone) {
+        return strcmp(v1->zone, v2->zone);
+    }
+
+    return 0;
+}
+
+/**
  * @brief Implementation of ::lyplg_type_print_clb for the ipv4-address ietf-inet-types type.
  */
 static const void *
@@ -364,7 +394,7 @@
         .plugin.store = lyplg_type_store_ipv4_address,
         .plugin.validate = NULL,
         .plugin.compare = lyplg_type_compare_ipv4_address,
-        .plugin.sort = NULL,
+        .plugin.sort = lyplg_type_sort_ipv4_address,
         .plugin.print = lyplg_type_print_ipv4_address,
         .plugin.duplicate = lyplg_type_dup_ipv4_address,
         .plugin.free = lyplg_type_free_ipv4_address,
diff --git a/src/plugins_types/ipv4_address_no_zone.c b/src/plugins_types/ipv4_address_no_zone.c
index 67db22b..5476c19 100644
--- a/src/plugins_types/ipv4_address_no_zone.c
+++ b/src/plugins_types/ipv4_address_no_zone.c
@@ -14,6 +14,7 @@
 
 #define _GNU_SOURCE /* strndup */
 
+#include "plugins_internal.h"
 #include "plugins_types.h"
 
 #ifdef _WIN32
@@ -26,6 +27,7 @@
 #    include <sys/socket.h>
 #  endif
 #endif
+#include <assert.h>
 #include <errno.h>
 #include <stdint.h>
 #include <stdlib.h>
@@ -143,6 +145,21 @@
 }
 
 /**
+ * @brief Implementation of ::lyplg_type_sort_clb for the ipv4-address-no-zone ietf-inet-types type.
+ */
+static int
+lyplg_type_sort_ipv4_address_no_zone(const struct ly_ctx *UNUSED(ctx), const struct lyd_value *val1,
+        const struct lyd_value *val2)
+{
+    struct lyd_value_ipv4_address_no_zone *v1, *v2;
+
+    LYD_VALUE_GET(val1, v1);
+    LYD_VALUE_GET(val2, v2);
+
+    return memcmp(&v1->addr, &v2->addr, sizeof v1->addr);
+}
+
+/**
  * @brief Implementation of ::lyplg_type_print_clb for the ipv4-address-no-zone ietf-inet-types type.
  */
 static const void *
@@ -208,7 +225,7 @@
         .plugin.store = lyplg_type_store_ipv4_address_no_zone,
         .plugin.validate = NULL,
         .plugin.compare = lyplg_type_compare_ipv4_address_no_zone,
-        .plugin.sort = NULL,
+        .plugin.sort = lyplg_type_sort_ipv4_address_no_zone,
         .plugin.print = lyplg_type_print_ipv4_address_no_zone,
         .plugin.duplicate = lyplg_type_dup_simple,
         .plugin.free = lyplg_type_free_simple,
diff --git a/src/plugins_types/ipv4_prefix.c b/src/plugins_types/ipv4_prefix.c
index d4fb785..2a86f36 100644
--- a/src/plugins_types/ipv4_prefix.c
+++ b/src/plugins_types/ipv4_prefix.c
@@ -14,6 +14,7 @@
 
 #define _GNU_SOURCE /* strndup */
 
+#include "plugins_internal.h"
 #include "plugins_types.h"
 
 #ifdef _WIN32
@@ -26,6 +27,7 @@
 #    include <sys/socket.h>
 #  endif
 #endif
+#include <assert.h>
 #include <stdint.h>
 #include <stdlib.h>
 #include <string.h>
@@ -214,6 +216,21 @@
 }
 
 /**
+ * @brief Implementation of ::lyplg_type_sort_clb for the ietf-inet-types ipv4-prefix type.
+ */
+static int
+lyplg_type_sort_ipv4_prefix(const struct ly_ctx *UNUSED(ctx), const struct lyd_value *val1,
+        const struct lyd_value *val2)
+{
+    struct lyd_value_ipv4_prefix *v1, *v2;
+
+    LYD_VALUE_GET(val1, v1);
+    LYD_VALUE_GET(val2, v2);
+
+    return memcmp(v1, v2, sizeof *v1);
+}
+
+/**
  * @brief Implementation of ::lyplg_type_compare_clb for the ietf-inet-types ipv4-prefix type.
  */
 static const void *
@@ -324,7 +341,7 @@
         .plugin.store = lyplg_type_store_ipv4_prefix,
         .plugin.validate = NULL,
         .plugin.compare = lyplg_type_compare_ipv4_prefix,
-        .plugin.sort = NULL,
+        .plugin.sort = lyplg_type_sort_ipv4_prefix,
         .plugin.print = lyplg_type_print_ipv4_prefix,
         .plugin.duplicate = lyplg_type_dup_ipv4_prefix,
         .plugin.free = lyplg_type_free_ipv4_prefix,
diff --git a/src/plugins_types/ipv6_address.c b/src/plugins_types/ipv6_address.c
index 9a2c31a..031bb8f 100644
--- a/src/plugins_types/ipv6_address.c
+++ b/src/plugins_types/ipv6_address.c
@@ -14,6 +14,7 @@
 
 #define _GNU_SOURCE /* strndup */
 
+#include "plugins_internal.h"
 #include "plugins_types.h"
 
 #ifdef _WIN32
@@ -26,6 +27,7 @@
 #    include <sys/socket.h>
 #  endif
 #endif
+#include <assert.h>
 #include <ctype.h>
 #include <errno.h>
 #include <stdint.h>
@@ -228,6 +230,35 @@
 }
 
 /**
+ * @brief Implementation of ::lyplg_type_sort_clb for the ipv6-address ietf-inet-types type.
+ */
+static int
+lyplg_type_sort_ipv6_address(const struct ly_ctx *UNUSED(ctx), const struct lyd_value *val1,
+        const struct lyd_value *val2)
+{
+    struct lyd_value_ipv6_address *v1, *v2;
+    int cmp;
+
+    LYD_VALUE_GET(val1, v1);
+    LYD_VALUE_GET(val2, v2);
+
+    cmp = memcmp(&v1->addr, &v2->addr, sizeof v1->addr);
+    if (cmp != 0) {
+        return cmp;
+    }
+
+    if (!v1->zone && v2->zone) {
+        return -1;
+    } else if (v1->zone && !v2->zone) {
+        return 1;
+    } else if (v1->zone && v2->zone) {
+        return strcmp(v1->zone, v2->zone);
+    }
+
+    return 0;
+}
+
+/**
  * @brief Implementation of ::lyplg_type_print_clb for the ipv6-address ietf-inet-types type.
  */
 static const void *
@@ -365,7 +396,7 @@
         .plugin.store = lyplg_type_store_ipv6_address,
         .plugin.validate = NULL,
         .plugin.compare = lyplg_type_compare_ipv6_address,
-        .plugin.sort = NULL,
+        .plugin.sort = lyplg_type_sort_ipv6_address,
         .plugin.print = lyplg_type_print_ipv6_address,
         .plugin.duplicate = lyplg_type_dup_ipv6_address,
         .plugin.free = lyplg_type_free_ipv6_address,
diff --git a/src/plugins_types/ipv6_address_no_zone.c b/src/plugins_types/ipv6_address_no_zone.c
index 56e0760..6b4f0e6 100644
--- a/src/plugins_types/ipv6_address_no_zone.c
+++ b/src/plugins_types/ipv6_address_no_zone.c
@@ -14,6 +14,7 @@
 
 #define _GNU_SOURCE /* strndup */
 
+#include "plugins_internal.h"
 #include "plugins_types.h"
 
 #ifdef _WIN32
@@ -26,6 +27,7 @@
 #    include <sys/socket.h>
 #  endif
 #endif
+#include <assert.h>
 #include <errno.h>
 #include <stdint.h>
 #include <stdlib.h>
@@ -191,6 +193,21 @@
 }
 
 /**
+ * @brief Implementation of ::lyplg_type_sort_clb for the ipv6-address-no-zone ietf-inet-types type.
+ */
+static int
+lyplg_type_sort_ipv6_address_no_zone(const struct ly_ctx *UNUSED(ctx), const struct lyd_value *val1,
+        const struct lyd_value *val2)
+{
+    struct lyd_value_ipv6_address_no_zone *v1, *v2;
+
+    LYD_VALUE_GET(val1, v1);
+    LYD_VALUE_GET(val2, v2);
+
+    return memcmp(&v1->addr, &v2->addr, sizeof v1->addr);
+}
+
+/**
  * @brief Implementation of ::lyplg_type_print_clb for the ipv6-address-no-zone ietf-inet-types type.
  */
 static const void *
@@ -299,7 +316,7 @@
         .plugin.store = lyplg_type_store_ipv6_address_no_zone,
         .plugin.validate = NULL,
         .plugin.compare = lyplg_type_compare_ipv6_address_no_zone,
-        .plugin.sort = NULL,
+        .plugin.sort = lyplg_type_sort_ipv6_address_no_zone,
         .plugin.print = lyplg_type_print_ipv6_address_no_zone,
         .plugin.duplicate = lyplg_type_dup_ipv6_address_no_zone,
         .plugin.free = lyplg_type_free_ipv6_address_no_zone,
diff --git a/src/plugins_types/ipv6_prefix.c b/src/plugins_types/ipv6_prefix.c
index d6823ad..05b1be7 100644
--- a/src/plugins_types/ipv6_prefix.c
+++ b/src/plugins_types/ipv6_prefix.c
@@ -14,6 +14,7 @@
 
 #define _GNU_SOURCE /* strndup */
 
+#include "plugins_internal.h"
 #include "plugins_types.h"
 
 #ifdef _WIN32
@@ -26,6 +27,7 @@
 #    include <sys/socket.h>
 #  endif
 #endif
+#include <assert.h>
 #include <stdint.h>
 #include <stdlib.h>
 #include <string.h>
@@ -228,6 +230,21 @@
 }
 
 /**
+ * @brief Implementation of ::lyplg_type_sort_clb for the ietf-inet-types ipv6-prefix type.
+ */
+static int
+lyplg_type_sort_ipv6_prefix(const struct ly_ctx *UNUSED(ctx), const struct lyd_value *val1,
+        const struct lyd_value *val2)
+{
+    struct lyd_value_ipv6_prefix *v1, *v2;
+
+    LYD_VALUE_GET(val1, v1);
+    LYD_VALUE_GET(val2, v2);
+
+    return memcmp(v1, v2, sizeof *v1);
+}
+
+/**
  * @brief Implementation of ::lyplg_type_compare_clb for the ietf-inet-types ipv6-prefix type.
  */
 static const void *
@@ -338,7 +355,7 @@
         .plugin.store = lyplg_type_store_ipv6_prefix,
         .plugin.validate = NULL,
         .plugin.compare = lyplg_type_compare_ipv6_prefix,
-        .plugin.sort = NULL,
+        .plugin.sort = lyplg_type_sort_ipv6_prefix,
         .plugin.print = lyplg_type_print_ipv6_prefix,
         .plugin.duplicate = lyplg_type_dup_ipv6_prefix,
         .plugin.free = lyplg_type_free_ipv6_prefix,
diff --git a/tests/utests/types/inet_types.c b/tests/utests/types/inet_types.c
index eb4e480..3874cc3 100644
--- a/tests/utests/types/inet_types.c
+++ b/tests/utests/types/inet_types.c
@@ -137,12 +137,147 @@
     TEST_SUCCESS_LYB("lyb", "l7", "::C:D:E:f:a/112");
 }
 
+static void
+test_plugin_sort(void **state)
+{
+    const char *v1, *v2;
+    const char *schema;
+    struct lys_module *mod;
+    struct lyd_value val1 = {0}, val2 = {0};
+    struct lyplg_type *type = lyplg_type_plugin_find("", NULL, ly_data_type2str[LY_TYPE_UNION]);
+    struct lysc_type *lysc_type;
+    struct ly_err_item *err = NULL;
+
+    schema = MODULE_CREATE_YANG("a",
+            "leaf l {type inet:ip-address;}"
+            "leaf l2 {type inet:ipv6-address;}"
+            "leaf l3 {type inet:ip-address-no-zone;}"
+            "leaf l4 {type inet:ipv6-address-no-zone;}"
+            "leaf l5 {type inet:ipv4-prefix;}"
+            "leaf l6 {type inet:ipv6-prefix;}");
+    UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, &mod);
+
+    /* ipv4-address */
+    lysc_type = ((struct lysc_node_leaf *)mod->compiled->data)->type;
+
+    v1 = "192.168.0.1";
+    assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, v1, strlen(v1),
+            0, LY_VALUE_JSON, NULL, LYD_VALHINT_STRING, NULL, &val1, NULL, &err));
+    v2 = "192.168.0.2";
+    assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, v2, strlen(v2),
+            0, LY_VALUE_JSON, NULL, LYD_VALHINT_STRING, NULL, &val2, NULL, &err));
+    assert_true(0 > type->sort(UTEST_LYCTX, &val1, &val2));
+    assert_int_equal(0, type->sort(UTEST_LYCTX, &val1, &val1));
+    assert_true(0 < type->sort(UTEST_LYCTX, &val2, &val1));
+    type->free(UTEST_LYCTX, &val1);
+    type->free(UTEST_LYCTX, &val2);
+
+    v1 = "192.168.0.1%1A";
+    assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, v1, strlen(v1),
+            0, LY_VALUE_JSON, NULL, LYD_VALHINT_STRING, NULL, &val1, NULL, &err));
+    v2 = "192.168.0.1";
+    assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, v2, strlen(v2),
+            0, LY_VALUE_JSON, NULL, LYD_VALHINT_STRING, NULL, &val2, NULL, &err));
+    assert_true(0 < type->sort(UTEST_LYCTX, &val1, &val2));
+    assert_int_equal(0, type->sort(UTEST_LYCTX, &val1, &val1));
+    assert_true(0 > type->sort(UTEST_LYCTX, &val2, &val1));
+    type->free(UTEST_LYCTX, &val1);
+    type->free(UTEST_LYCTX, &val2);
+
+    /* ipv6-address */
+    lysc_type = ((struct lysc_node_leaflist *)mod->compiled->data->next)->type;
+    type = lyplg_type_plugin_find("", NULL, ly_data_type2str[LY_TYPE_STRING]);
+
+    v1 = "2008:15:0:0:0:0:feAC:1";
+    assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, v1, strlen(v1),
+            0, LY_VALUE_JSON, NULL, LYD_VALHINT_STRING, NULL, &val1, NULL, &err));
+    v2 = "2008:15::feac:2";
+    assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, v2, strlen(v2),
+            0, LY_VALUE_JSON, NULL, LYD_VALHINT_STRING, NULL, &val2, NULL, &err));
+    assert_true(0 > type->sort(UTEST_LYCTX, &val1, &val2));
+    assert_int_equal(0, type->sort(UTEST_LYCTX, &val1, &val1));
+    assert_true(0 < type->sort(UTEST_LYCTX, &val2, &val1));
+    type->free(UTEST_LYCTX, &val1);
+    type->free(UTEST_LYCTX, &val2);
+
+    v1 = "FAAC:21:011:Da85::87:daaF%1";
+    assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, v1, strlen(v1),
+            0, LY_VALUE_JSON, NULL, LYD_VALHINT_STRING, NULL, &val1, NULL, &err));
+    v2 = "FAAC:21:011:Da85::87:daaF%14";
+    assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, v2, strlen(v2),
+            0, LY_VALUE_JSON, NULL, LYD_VALHINT_STRING, NULL, &val2, NULL, &err));
+    assert_true(0 > type->sort(UTEST_LYCTX, &val1, &val2));
+    assert_int_equal(0, type->sort(UTEST_LYCTX, &val1, &val1));
+    assert_true(0 < type->sort(UTEST_LYCTX, &val2, &val1));
+    type->free(UTEST_LYCTX, &val1);
+    type->free(UTEST_LYCTX, &val2);
+
+    /* ipv4-address-no-zone */
+    lysc_type = ((struct lysc_node_leaflist *)mod->compiled->data->next->next)->type;
+    type = lyplg_type_plugin_find("", NULL, ly_data_type2str[LY_TYPE_UNION]);
+    v1 = "127.0.0.1";
+    assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, v1, strlen(v1),
+            0, LY_VALUE_JSON, NULL, LYD_VALHINT_STRING, NULL, &val1, NULL, &err));
+    v2 = "127.0.1.1";
+    assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, v2, strlen(v2),
+            0, LY_VALUE_JSON, NULL, LYD_VALHINT_STRING, NULL, &val2, NULL, &err));
+    assert_true(0 > type->sort(UTEST_LYCTX, &val1, &val2));
+    assert_int_equal(0, type->sort(UTEST_LYCTX, &val1, &val1));
+    assert_true(0 < type->sort(UTEST_LYCTX, &val2, &val1));
+    type->free(UTEST_LYCTX, &val1);
+    type->free(UTEST_LYCTX, &val2);
+
+    /* ipv6-address-no-zone */
+    lysc_type = ((struct lysc_node_leaflist *)mod->compiled->data->next->next->next)->type;
+    type = lyplg_type_plugin_find("", NULL, ly_data_type2str[LY_TYPE_STRING]);
+    v1 = "A:B:c:D:e:f:1:1";
+    assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, v1, strlen(v1),
+            0, LY_VALUE_JSON, NULL, LYD_VALHINT_STRING, NULL, &val1, NULL, &err));
+    v2 = "A:B:c:D:e:f:1:0";
+    assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, v2, strlen(v2),
+            0, LY_VALUE_JSON, NULL, LYD_VALHINT_STRING, NULL, &val2, NULL, &err));
+    assert_true(0 < type->sort(UTEST_LYCTX, &val1, &val2));
+    assert_int_equal(0, type->sort(UTEST_LYCTX, &val1, &val1));
+    assert_true(0 > type->sort(UTEST_LYCTX, &val2, &val1));
+    type->free(UTEST_LYCTX, &val1);
+    type->free(UTEST_LYCTX, &val2);
+
+    /* ipv4-prefix */
+    lysc_type = ((struct lysc_node_leaflist *)mod->compiled->data->next->next->next->next)->type;
+    v1 = "0.1.58.4/32";
+    assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, v1, strlen(v1),
+            0, LY_VALUE_JSON, NULL, LYD_VALHINT_STRING, NULL, &val1, NULL, &err));
+    v2 = "0.1.58.4/16";
+    assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, v2, strlen(v2),
+            0, LY_VALUE_JSON, NULL, LYD_VALHINT_STRING, NULL, &val2, NULL, &err));
+    assert_true(0 < type->sort(UTEST_LYCTX, &val1, &val2));
+    assert_int_equal(0, type->sort(UTEST_LYCTX, &val1, &val1));
+    assert_true(0 > type->sort(UTEST_LYCTX, &val2, &val1));
+    type->free(UTEST_LYCTX, &val1);
+    type->free(UTEST_LYCTX, &val2);
+
+    /* ipv6-prefix */
+    lysc_type = ((struct lysc_node_leaflist *)mod->compiled->data->next->next->next->next->next)->type;
+    v1 = "::C:D:E:f:a/96";
+    assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, v1, strlen(v1),
+            0, LY_VALUE_JSON, NULL, LYD_VALHINT_STRING, NULL, &val1, NULL, &err));
+    v2 = "::C:D:E:f:a/112";
+    assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, v2, strlen(v2),
+            0, LY_VALUE_JSON, NULL, LYD_VALHINT_STRING, NULL, &val2, NULL, &err));
+    assert_true(0 < type->sort(UTEST_LYCTX, &val1, &val2));
+    assert_int_equal(0, type->sort(UTEST_LYCTX, &val1, &val1));
+    assert_true(0 > type->sort(UTEST_LYCTX, &val2, &val1));
+    type->free(UTEST_LYCTX, &val1);
+    type->free(UTEST_LYCTX, &val2);
+}
+
 int
 main(void)
 {
     const struct CMUnitTest tests[] = {
         UTEST(test_data_xml),
         UTEST(test_data_lyb),
+        UTEST(test_plugin_sort),
     };
 
     return cmocka_run_group_tests(tests, NULL, NULL);