summary refs log tree commit diff
path: root/src/core/tests
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2022-01-13 22:30:39 +0100
committerMichael Biebl <biebl@debian.org>2022-01-13 22:30:39 +0100
commit88c227d90a6b7b388c5c85d72802a0ca8f05ed5c (patch)
tree71f32df6617802270e8a78574bd8e1637dc532f4 /src/core/tests
parente74c568b07b50b97873fb4ee1d776dedefbd54d6 (diff)
New upstream version 1.34.0 upstream/1.34.0
Diffstat (limited to 'src/core/tests')
-rw-r--r--src/core/tests/test-core.c168
-rw-r--r--src/core/tests/test-ip6-config.c12
-rw-r--r--src/core/tests/test-l3cfg.c317
-rw-r--r--src/core/tests/test-systemd.c8
-rw-r--r--src/core/tests/test-utils.c75
5 files changed, 434 insertions, 146 deletions
diff --git a/src/core/tests/test-core.c b/src/core/tests/test-core.c
index f28c4178..3524cb17 100644
--- a/src/core/tests/test-core.c
+++ b/src/core/tests/test-core.c
@@ -1728,86 +1728,86 @@ test_nm_utils_strbuf_append(void)
     char buf[NM_STRLEN(BUF_ORIG) + 1];
     char str[NM_STRLEN(BUF_ORIG) + 1];
 
-#define _strbuf_append(buf, len, format, ...)                           \
-    G_STMT_START                                                        \
-    {                                                                   \
-        char **       _buf = (buf);                                     \
-        gsize *       _len = (len);                                     \
-        const char *  _str_iter;                                        \
-        gs_free char *_str = NULL;                                      \
-                                                                        \
-        switch (nmtst_get_rand_uint32() % 4) {                          \
-        case 0:                                                         \
-            nm_utils_strbuf_append(_buf, _len, (format), __VA_ARGS__);  \
-            break;                                                      \
-        case 1:                                                         \
-            _str = g_strdup_printf((format), __VA_ARGS__);              \
-            nm_utils_strbuf_append_str(_buf, _len, _str);               \
-            break;                                                      \
-        case 2:                                                         \
-            _str = g_strdup_printf((format), __VA_ARGS__);              \
-            nm_utils_strbuf_append_bin(_buf, _len, _str, strlen(_str)); \
-            break;                                                      \
-        case 3:                                                         \
-            _str = g_strdup_printf((format), __VA_ARGS__);              \
-            if (!_str[0])                                               \
-                nm_utils_strbuf_append_str(_buf, _len, _str);           \
-            for (_str_iter = _str; _str_iter[0]; _str_iter++)           \
-                nm_utils_strbuf_append_c(_buf, _len, _str_iter[0]);     \
-            break;                                                      \
-        }                                                               \
-    }                                                                   \
+#define _strbuf_append(buf, len, format, ...)                     \
+    G_STMT_START                                                  \
+    {                                                             \
+        char **       _buf = (buf);                               \
+        gsize *       _len = (len);                               \
+        const char *  _str_iter;                                  \
+        gs_free char *_str = NULL;                                \
+                                                                  \
+        switch (nmtst_get_rand_uint32() % 4) {                    \
+        case 0:                                                   \
+            nm_strbuf_append(_buf, _len, (format), __VA_ARGS__);  \
+            break;                                                \
+        case 1:                                                   \
+            _str = g_strdup_printf((format), __VA_ARGS__);        \
+            nm_strbuf_append_str(_buf, _len, _str);               \
+            break;                                                \
+        case 2:                                                   \
+            _str = g_strdup_printf((format), __VA_ARGS__);        \
+            nm_strbuf_append_bin(_buf, _len, _str, strlen(_str)); \
+            break;                                                \
+        case 3:                                                   \
+            _str = g_strdup_printf((format), __VA_ARGS__);        \
+            if (!_str[0])                                         \
+                nm_strbuf_append_str(_buf, _len, _str);           \
+            for (_str_iter = _str; _str_iter[0]; _str_iter++)     \
+                nm_strbuf_append_c(_buf, _len, _str_iter[0]);     \
+            break;                                                \
+        }                                                         \
+    }                                                             \
     G_STMT_END
 
-#define _strbuf_append_str(buf, len, str)                                          \
-    G_STMT_START                                                                   \
-    {                                                                              \
-        char **     _buf = (buf);                                                  \
-        gsize *     _len = (len);                                                  \
-        const char *_str = (str);                                                  \
-                                                                                   \
-        switch (nmtst_get_rand_uint32() % 4) {                                     \
-        case 0:                                                                    \
-            nm_utils_strbuf_append(_buf, _len, "%s", _str ?: "");                  \
-            break;                                                                 \
-        case 1:                                                                    \
-            nm_utils_strbuf_append_str(_buf, _len, _str);                          \
-            break;                                                                 \
-        case 2:                                                                    \
-            nm_utils_strbuf_append_bin(_buf, _len, _str, _str ? strlen(_str) : 0); \
-            break;                                                                 \
-        case 3:                                                                    \
-            if (!_str || !_str[0])                                                 \
-                nm_utils_strbuf_append_str(_buf, _len, _str);                      \
-            for (; _str && _str[0]; _str++)                                        \
-                nm_utils_strbuf_append_c(_buf, _len, _str[0]);                     \
-            break;                                                                 \
-        }                                                                          \
-    }                                                                              \
+#define _strbuf_append_str(buf, len, str)                                    \
+    G_STMT_START                                                             \
+    {                                                                        \
+        char **     _buf = (buf);                                            \
+        gsize *     _len = (len);                                            \
+        const char *_str = (str);                                            \
+                                                                             \
+        switch (nmtst_get_rand_uint32() % 4) {                               \
+        case 0:                                                              \
+            nm_strbuf_append(_buf, _len, "%s", _str ?: "");                  \
+            break;                                                           \
+        case 1:                                                              \
+            nm_strbuf_append_str(_buf, _len, _str);                          \
+            break;                                                           \
+        case 2:                                                              \
+            nm_strbuf_append_bin(_buf, _len, _str, _str ? strlen(_str) : 0); \
+            break;                                                           \
+        case 3:                                                              \
+            if (!_str || !_str[0])                                           \
+                nm_strbuf_append_str(_buf, _len, _str);                      \
+            for (; _str && _str[0]; _str++)                                  \
+                nm_strbuf_append_c(_buf, _len, _str[0]);                     \
+            break;                                                           \
+        }                                                                    \
+    }                                                                        \
     G_STMT_END
 
-#define _strbuf_append_c(buf, len, ch)                                   \
-    G_STMT_START                                                         \
-    {                                                                    \
-        char **_buf = (buf);                                             \
-        gsize *_len = (len);                                             \
-        char   _ch  = (ch);                                              \
-                                                                         \
-        switch (nmtst_get_rand_uint32() % 4) {                           \
-        case 0:                                                          \
-            nm_utils_strbuf_append(_buf, _len, "%c", _ch);               \
-            break;                                                       \
-        case 1:                                                          \
-            nm_utils_strbuf_append_str(_buf, _len, ((char[2]){_ch, 0})); \
-            break;                                                       \
-        case 2:                                                          \
-            nm_utils_strbuf_append_bin(_buf, _len, &_ch, 1);             \
-            break;                                                       \
-        case 3:                                                          \
-            nm_utils_strbuf_append_c(_buf, _len, _ch);                   \
-            break;                                                       \
-        }                                                                \
-    }                                                                    \
+#define _strbuf_append_c(buf, len, ch)                             \
+    G_STMT_START                                                   \
+    {                                                              \
+        char **_buf = (buf);                                       \
+        gsize *_len = (len);                                       \
+        char   _ch  = (ch);                                        \
+                                                                   \
+        switch (nmtst_get_rand_uint32() % 4) {                     \
+        case 0:                                                    \
+            nm_strbuf_append(_buf, _len, "%c", _ch);               \
+            break;                                                 \
+        case 1:                                                    \
+            nm_strbuf_append_str(_buf, _len, ((char[2]){_ch, 0})); \
+            break;                                                 \
+        case 2:                                                    \
+            nm_strbuf_append_bin(_buf, _len, &_ch, 1);             \
+            break;                                                 \
+        case 3:                                                    \
+            nm_strbuf_append_c(_buf, _len, _ch);                   \
+            break;                                                 \
+        }                                                          \
+    }                                                              \
     G_STMT_END
 
     for (buf_len = 0; buf_len < 10; buf_len++) {
@@ -1854,28 +1854,28 @@ test_nm_utils_strbuf_append(void)
                 if (t_len > 0 && strlen(str) >= buf_len && (nmtst_get_rand_uint32() % 2)) {
                     /* the string was truncated by g_snprintf(). That means, at the last position in the
                      * buffer is now NUL.
-                     * Replace the NUL by the actual character, and check that nm_utils_strbuf_seek_end()
+                     * Replace the NUL by the actual character, and check that nm_strbuf_seek_end()
                      * does the right thing: NUL terminate the buffer and seek past the end of the buffer. */
                     g_assert_cmpmem(t_buf, t_len - 1, str, t_len - 1);
                     g_assert(t_buf[t_len - 1] == '\0');
                     g_assert(str[t_len - 1] != '\0');
                     t_buf[t_len - 1] = str[t_len - 1];
-                    nm_utils_strbuf_seek_end(&t_buf, &t_len);
+                    nm_strbuf_seek_end(&t_buf, &t_len);
                     g_assert(t_len == 0);
                     g_assert(t_buf == &buf[buf_len]);
                     g_assert(t_buf[-1] == '\0');
                 } else {
-                    nm_utils_strbuf_seek_end(&t_buf, &t_len);
+                    nm_strbuf_seek_end(&t_buf, &t_len);
                     if (buf_len > 0 && strlen(str) + 1 > buf_len) {
                         /* the buffer was truncated by g_snprintf() above.
                          *
-                         * But nm_utils_strbuf_seek_end() does not recognize that and returns
+                         * But nm_strbuf_seek_end() does not recognize that and returns
                          * a remaining length of 1.
                          *
-                         * Note that other nm_utils_strbuf_append*() functions recognize
+                         * Note that other nm_strbuf_append*() functions recognize
                          * truncation, and properly set the remaining length to zero.
-                         * As the assertions below check for the behavior of nm_utils_strbuf_append*(),
-                         * we assert here that nm_utils_strbuf_seek_end() behaved as expected, and then
+                         * As the assertions below check for the behavior of nm_strbuf_append*(),
+                         * we assert here that nm_strbuf_seek_end() behaved as expected, and then
                          * adjust t_buf/t_len according to the "is-truncated" case. */
                         g_assert(t_len == 1);
                         g_assert(t_buf == &buf[buf_len - 1]);
@@ -2594,7 +2594,7 @@ main(int argc, char **argv)
     g_test_add_func("/general/test_logging_domains", test_logging_domains);
     g_test_add_func("/general/test_logging_error", test_logging_error);
 
-    g_test_add_func("/general/nm_utils_strbuf_append", test_nm_utils_strbuf_append);
+    g_test_add_func("/general/nm_strbuf_append", test_nm_utils_strbuf_append);
 
     g_test_add_func("/general/nm_utils_ip6_address_clear_host_address",
                     test_nm_utils_ip6_address_clear_host_address);
diff --git a/src/core/tests/test-ip6-config.c b/src/core/tests/test-ip6-config.c
index ddf4c789..2e6d8aaa 100644
--- a/src/core/tests/test-ip6-config.c
+++ b/src/core/tests/test-ip6-config.c
@@ -327,7 +327,7 @@ test_nm_ip6_config_addresses_sort(void)
              0,
              0,
              0,
-             IFA_F_TEMPORARY);
+             IFA_F_SECONDARY);
     ADDR_ADD("2607:f0d0:1002:51::8",
              NULL,
              64,
@@ -336,7 +336,7 @@ test_nm_ip6_config_addresses_sort(void)
              0,
              0,
              0,
-             IFA_F_TEMPORARY);
+             IFA_F_SECONDARY);
     ADDR_ADD("2607:f0d0:1002:51::0",
              NULL,
              64,
@@ -345,7 +345,7 @@ test_nm_ip6_config_addresses_sort(void)
              0,
              0,
              0,
-             IFA_F_TEMPORARY);
+             IFA_F_SECONDARY);
     ADDR_ADD("fec0::1", NULL, 128, 0, NM_IP_CONFIG_SOURCE_KERNEL, 0, 0, 0, 0);
     ADDR_ADD("fe80::208:74ff:feda:625c", NULL, 128, 0, NM_IP_CONFIG_SOURCE_KERNEL, 0, 0, 0, 0);
     ADDR_ADD("fe80::208:74ff:feda:625d", NULL, 128, 0, NM_IP_CONFIG_SOURCE_KERNEL, 0, 0, 0, 0);
@@ -374,7 +374,7 @@ test_nm_ip6_config_addresses_sort(void)
              0,
              0,
              0,
-             IFA_F_TEMPORARY);
+             IFA_F_SECONDARY);
     ADDR_ADD("2607:f0d0:1002:51::4", NULL, 64, 0, NM_IP_CONFIG_SOURCE_USER, 0, 0, 0, 0);
     ADDR_ADD("2607:f0d0:1002:51::5", NULL, 64, 0, NM_IP_CONFIG_SOURCE_USER, 0, 0, 0, 0);
     ADDR_ADD("2607:f0d0:1002:51::8",
@@ -385,7 +385,7 @@ test_nm_ip6_config_addresses_sort(void)
              0,
              0,
              0,
-             IFA_F_TEMPORARY);
+             IFA_F_SECONDARY);
     ADDR_ADD("2607:f0d0:1002:51::0",
              NULL,
              64,
@@ -394,7 +394,7 @@ test_nm_ip6_config_addresses_sort(void)
              0,
              0,
              0,
-             IFA_F_TEMPORARY);
+             IFA_F_SECONDARY);
     ADDR_ADD("2607:f0d0:1002:51::6",
              NULL,
              64,
diff --git a/src/core/tests/test-l3cfg.c b/src/core/tests/test-l3cfg.c
index ba065c09..100c2496 100644
--- a/src/core/tests/test-l3cfg.c
+++ b/src/core/tests/test-l3cfg.c
@@ -2,8 +2,11 @@
 
 #include "src/core/nm-default-daemon.h"
 
+#include <linux/if_addr.h>
+
 #include "nm-l3cfg.h"
 #include "nm-l3-ipv4ll.h"
+#include "nm-l3-ipv6ll.h"
 #include "nm-netns.h"
 #include "libnm-platform/nm-platform.h"
 
@@ -132,6 +135,7 @@ typedef struct {
     NML3AcdDefendType acd_defend_type_a;
 
     TestL3cfgNotifyType notify_type;
+    guint               pre_commit_event_count;
     guint               post_commit_event_count;
     guint               general_event_count;
     guint               general_event_flags;
@@ -151,6 +155,7 @@ _test_l3cfg_data_set_notify_type(TestL3cfgData *tdata, TestL3cfgNotifyType notif
     g_assert(tdata);
 
     tdata->notify_type             = notify_type;
+    tdata->pre_commit_event_count  = 0;
     tdata->post_commit_event_count = 0;
     tdata->general_event_count     = 0;
     tdata->general_event_flags     = 0;
@@ -209,6 +214,10 @@ _test_l3cfg_signal_notify(NML3Cfg *                   l3cfg,
     case TEST_L3CFG_NOTIFY_TYPE_COMMIT_1:
         g_assert_cmpint(tdata->post_commit_event_count, ==, 0);
         switch (notify_data->notify_type) {
+        case NM_L3_CONFIG_NOTIFY_TYPE_PRE_COMMIT:
+            g_assert_cmpint(tdata->pre_commit_event_count, ==, 0);
+            tdata->pre_commit_event_count++;
+            return;
         case NM_L3_CONFIG_NOTIFY_TYPE_POST_COMMIT:
             tdata->post_commit_event_count++;
             return;
@@ -255,6 +264,7 @@ _test_l3cfg_signal_notify(NML3Cfg *                   l3cfg,
             1 + 2 + (tdata->add_addr4_101 ? (tdata->has_addr4_101 ? 1 : 3) : 0);
 
         if (NM_IN_SET(notify_data->notify_type,
+                      NM_L3_CONFIG_NOTIFY_TYPE_PRE_COMMIT,
                       NM_L3_CONFIG_NOTIFY_TYPE_PLATFORM_CHANGE,
                       NM_L3_CONFIG_NOTIFY_TYPE_PLATFORM_CHANGE_ON_IDLE))
             return;
@@ -368,7 +378,8 @@ test_l3cfg(gconstpointer test_data)
 
     g_signal_connect(l3cfg0, NM_L3CFG_SIGNAL_NOTIFY, G_CALLBACK(_test_l3cfg_signal_notify), tdata);
 
-    commit_type_1 = nm_l3cfg_commit_type_register(l3cfg0, NM_L3_CFG_COMMIT_TYPE_UPDATE, NULL);
+    commit_type_1 =
+        nm_l3cfg_commit_type_register(l3cfg0, NM_L3_CFG_COMMIT_TYPE_UPDATE, NULL, "test1");
 
     if (!nmtst_get_rand_one_case_in(4)) {
         commit_type_2 =
@@ -376,7 +387,8 @@ test_l3cfg(gconstpointer test_data)
                                           nmtst_rand_select(NM_L3_CFG_COMMIT_TYPE_NONE,
                                                             NM_L3_CFG_COMMIT_TYPE_ASSUME,
                                                             NM_L3_CFG_COMMIT_TYPE_UPDATE),
-                                          NULL);
+                                          NULL,
+                                          "test2");
     } else
         commit_type_2 = NULL;
 
@@ -389,7 +401,7 @@ test_l3cfg(gconstpointer test_data)
     {
         nm_auto_unref_l3cd_init NML3ConfigData *l3cd = NULL;
 
-        l3cd = nm_l3_config_data_new(f->multiidx, f->ifindex0);
+        l3cd = nm_l3_config_data_new(f->multiidx, f->ifindex0, NM_IP_CONFIG_SOURCE_UNKNOWN);
 
         nm_l3_config_data_add_address_4(
             l3cd,
@@ -432,8 +444,11 @@ test_l3cfg(gconstpointer test_data)
                             NM_PLATFORM_ROUTE_METRIC_DEFAULT_IP6,
                             0,
                             0,
+                            NM_DNS_PRIORITY_DEFAULT_NORMAL,
+                            NM_DNS_PRIORITY_DEFAULT_NORMAL,
                             tdata->acd_defend_type_a,
                             tdata->acd_timeout_msec_a,
+                            NM_L3CFG_CONFIG_FLAGS_NONE,
                             NM_L3_CONFIG_MERGE_FLAGS_NONE);
     }
 
@@ -445,6 +460,7 @@ test_l3cfg(gconstpointer test_data)
 
     _test_l3cfg_data_set_notify_type(tdata, TEST_L3CFG_NOTIFY_TYPE_COMMIT_1);
     nm_l3cfg_commit(l3cfg0, NM_L3_CFG_COMMIT_TYPE_REAPPLY);
+    g_assert_cmpint(tdata->pre_commit_event_count, ==, 1);
     g_assert_cmpint(tdata->post_commit_event_count, ==, 1);
     _test_l3cfg_data_set_notify_type(tdata, TEST_L3CFG_NOTIFY_TYPE_NONE);
 
@@ -490,7 +506,7 @@ test_l3cfg(gconstpointer test_data)
     if (nmtst_get_rand_one_case_in(3))
         _test_fixture_1_teardown(&test_fixture);
 
-    nm_l3cfg_remove_config_all(l3cfg0, GINT_TO_POINTER('a'), FALSE);
+    nm_l3cfg_remove_config_all(l3cfg0, GINT_TO_POINTER('a'));
 
     if (nmtst_get_rand_one_case_in(3))
         _test_fixture_1_teardown(&test_fixture);
@@ -593,16 +609,21 @@ _test_l3_ipv4ll_signal_notify(NML3Cfg *                   l3cfg,
                                          105,
                                          0,
                                          0,
+                                         NM_DNS_PRIORITY_DEFAULT_NORMAL,
+                                         NM_DNS_PRIORITY_DEFAULT_NORMAL,
                                          NM_L3_ACD_DEFEND_TYPE_ONCE,
                                          nmtst_get_rand_bool() ? tdata->acd_timeout_msec : 0u,
+                                         NM_L3CFG_CONFIG_FLAGS_NONE,
                                          NM_L3_CONFIG_MERGE_FLAGS_NONE))
                     g_assert_not_reached();
-                nm_l3cfg_commit_on_idle_schedule(nm_l3_ipv4ll_get_l3cfg(tdata->l3ipv4ll));
+                nm_l3cfg_commit_on_idle_schedule(nm_l3_ipv4ll_get_l3cfg(tdata->l3ipv4ll),
+                                                 NM_L3_CFG_COMMIT_TYPE_AUTO);
 
                 tdata->l3cfg_commit_type_1 =
                     nm_l3cfg_commit_type_register(nm_l3_ipv4ll_get_l3cfg(tdata->l3ipv4ll),
                                                   NM_L3_CFG_COMMIT_TYPE_UPDATE,
-                                                  tdata->l3cfg_commit_type_1);
+                                                  tdata->l3cfg_commit_type_1,
+                                                  "test");
             }
         } else if (nm_l3_ipv4ll_get_state(tdata->l3ipv4ll) != NM_L3_IPV4LL_STATE_DEFENDING
                    && tdata->ready_seen > 0) {
@@ -615,10 +636,10 @@ _test_l3_ipv4ll_signal_notify(NML3Cfg *                   l3cfg,
                 _LOGT("remove address %s that previously passed ACD",
                       _nm_utils_inet4_ntop(tdata->addr_commit_addr, sbuf_addr));
                 if (!nm_l3cfg_remove_config_all(nm_l3_ipv4ll_get_l3cfg(tdata->l3ipv4ll),
-                                                TEST_L3_IPV4LL_TAG(tdata, 1),
-                                                FALSE))
+                                                TEST_L3_IPV4LL_TAG(tdata, 1)))
                     g_assert_not_reached();
-                nm_l3cfg_commit_on_idle_schedule(nm_l3_ipv4ll_get_l3cfg(tdata->l3ipv4ll));
+                nm_l3cfg_commit_on_idle_schedule(nm_l3_ipv4ll_get_l3cfg(tdata->l3ipv4ll),
+                                                 NM_L3_CFG_COMMIT_TYPE_AUTO);
                 nm_l3cfg_commit_type_unregister(nm_l3_ipv4ll_get_l3cfg(tdata->l3ipv4ll),
                                                 g_steal_pointer(&tdata->l3cfg_commit_type_1));
             }
@@ -766,9 +787,7 @@ test_l3_ipv4ll(gconstpointer test_data)
     _LOGT("poll 1 end");
 
     if (tdata->addr_commit || nmtst_get_rand_bool()) {
-        nm_l3cfg_remove_config_all(nm_l3_ipv4ll_get_l3cfg(l3ipv4ll),
-                                   TEST_L3_IPV4LL_TAG(tdata, 1),
-                                   FALSE);
+        nm_l3cfg_remove_config_all(nm_l3_ipv4ll_get_l3cfg(l3ipv4ll), TEST_L3_IPV4LL_TAG(tdata, 1));
     }
 
     nmtstp_acd_defender_destroy(g_steal_pointer(&acd_defender_1));
@@ -781,6 +800,276 @@ test_l3_ipv4ll(gconstpointer test_data)
 
 /*****************************************************************************/
 
+#define _LLADDR_TEST1 "fe80::dd5a:8a44:48bc:3ad"
+#define _LLADDR_TEST2 "fe80::878b:938e:46f9:4807"
+
+typedef struct {
+    const TestFixture1 *f;
+    NML3Cfg *           l3cfg0;
+    NML3IPv6LL *        l3ipv6ll;
+    int                 step;
+    int                 ipv6ll_callback_step;
+    bool                steps_done : 1;
+    const NMPObject *   lladdr0;
+} TestL3IPv6LLData;
+
+static const NMPlatformIP6Address *
+_test_l3_ipv6ll_find_lladdr(TestL3IPv6LLData *tdata, int ifindex)
+{
+    const NMPlatformIP6Address *found = NULL;
+    NMDedupMultiIter            iter;
+    const NMPObject *           obj;
+    NMPLookup                   lookup;
+
+    g_assert(tdata);
+
+    nmp_lookup_init_object(&lookup, NMP_OBJECT_TYPE_IP6_ADDRESS, ifindex);
+    nm_platform_iter_obj_for_each (&iter, tdata->f->platform, &lookup, &obj) {
+        const NMPlatformIP6Address *a = NMP_OBJECT_CAST_IP6_ADDRESS(obj);
+
+        if (!IN6_IS_ADDR_LINKLOCAL(&a->address))
+            continue;
+
+        if (!found)
+            found = a;
+        else
+            g_assert_not_reached();
+    }
+
+    return found;
+}
+
+static const NMPObject *
+_test_l3_ipv6ll_find_lladdr_wait(TestL3IPv6LLData *tdata, int ifindex)
+{
+    const NMPObject *obj = NULL;
+
+    nmtst_main_context_iterate_until_assert(NULL, 3000, ({
+                                                const NMPlatformIP6Address *a;
+
+                                                a = _test_l3_ipv6ll_find_lladdr(tdata, ifindex);
+                                                if (a
+                                                    && !NM_FLAGS_HAS(a->n_ifa_flags,
+                                                                     IFA_F_TENTATIVE))
+                                                    obj = NMP_OBJECT_UP_CAST(a);
+                                                obj;
+                                            }));
+
+    return obj;
+}
+
+static const NMPlatformIP6Address *
+_test_l3_ipv6ll_find_inet6(TestL3IPv6LLData *tdata, const struct in6_addr *addr)
+{
+    const NMPlatformIP6Address *a;
+
+    a = nmtstp_platform_ip6_address_find(nm_l3cfg_get_platform(tdata->l3cfg0),
+                                         nmtst_get_rand_bool() ? 0 : tdata->f->ifindex0,
+                                         addr);
+    if (a) {
+        g_assert_cmpint(a->ifindex, ==, tdata->f->ifindex0);
+        g_assert_cmpmem(addr, sizeof(*addr), &a->address, sizeof(a->address));
+    }
+
+    g_assert(a
+             == nm_platform_ip6_address_get(nm_l3cfg_get_platform(tdata->l3cfg0),
+                                            tdata->f->ifindex0,
+                                            addr));
+
+    return a;
+}
+
+static void
+_test_l3_ipv6ll_signal_notify(NML3Cfg *                   l3cfg,
+                              const NML3ConfigNotifyData *notify_data,
+                              TestL3IPv6LLData *          tdata)
+{
+    g_assert_cmpint(tdata->step, >=, 1);
+    g_assert_cmpint(tdata->step, <=, 2);
+}
+
+static void
+_test_l3_ipv6ll_callback_changed(NML3IPv6LL *           ipv6ll,
+                                 NML3IPv6LLState        state,
+                                 const struct in6_addr *lladdr,
+                                 gpointer               user_data)
+{
+    TestL3IPv6LLData *          tdata = user_data;
+    int                         step  = tdata->ipv6ll_callback_step++;
+    const NMPlatformIP6Address *a1;
+
+    g_assert_cmpint(tdata->step, ==, 1);
+    g_assert(!tdata->steps_done);
+
+    switch (step) {
+    case 0:
+        if (NM_IN_SET(tdata->f->test_idx, 1, 2, 4)) {
+            g_assert_cmpint(state, ==, NM_L3_IPV6LL_STATE_DAD_IN_PROGRESS);
+            g_assert_cmpstr(nmtst_inet6_to_string(lladdr), ==, _LLADDR_TEST1);
+        } else if (NM_IN_SET(tdata->f->test_idx, 3)) {
+            g_assert_cmpint(state, ==, NM_L3_IPV6LL_STATE_READY);
+            g_assert(
+                IN6_ARE_ADDR_EQUAL(lladdr, &NMP_OBJECT_CAST_IP6_ADDRESS(tdata->lladdr0)->address));
+            tdata->steps_done = TRUE;
+        } else
+            g_assert_not_reached();
+        break;
+    case 1:
+        if (NM_IN_SET(tdata->f->test_idx, 1, 2)) {
+            g_assert_cmpint(state, ==, NM_L3_IPV6LL_STATE_READY);
+            g_assert_cmpstr(nmtst_inet6_to_string(lladdr), ==, _LLADDR_TEST1);
+            a1 = _test_l3_ipv6ll_find_inet6(tdata, lladdr);
+            g_assert(a1);
+            g_assert(!NM_FLAGS_HAS(a1->n_ifa_flags, IFA_F_TENTATIVE));
+            tdata->steps_done = TRUE;
+        } else if (NM_IN_SET(tdata->f->test_idx, 4)) {
+            g_assert_cmpint(state, ==, NM_L3_IPV6LL_STATE_DAD_IN_PROGRESS);
+            g_assert_cmpstr(nmtst_inet6_to_string(lladdr), ==, _LLADDR_TEST2);
+        } else
+            g_assert_not_reached();
+        break;
+    case 2:
+        if (NM_IN_SET(tdata->f->test_idx, 4)) {
+            g_assert_cmpint(state, ==, NM_L3_IPV6LL_STATE_READY);
+            g_assert_cmpstr(nmtst_inet6_to_string(lladdr), ==, _LLADDR_TEST2);
+            a1 = _test_l3_ipv6ll_find_inet6(tdata, lladdr);
+            g_assert(a1);
+            g_assert(!NM_FLAGS_HAS(a1->n_ifa_flags, IFA_F_TENTATIVE));
+            tdata->steps_done = TRUE;
+        } else
+            g_assert_not_reached();
+        break;
+    default:
+        g_assert_not_reached();
+    }
+}
+
+static void
+test_l3_ipv6ll(gconstpointer test_data)
+{
+    NMTST_UTILS_HOST_ID_CONTEXT("l3-ipv6ll");
+    const int                                      TEST_IDX     = GPOINTER_TO_INT(test_data);
+    nm_auto(_test_fixture_1_teardown) TestFixture1 test_fixture = {};
+    gs_unref_object NML3Cfg *l3cfg0                             = NULL;
+    TestL3IPv6LLData         tdata_stack                        = {
+        .step       = 0,
+        .steps_done = FALSE,
+    };
+    TestL3IPv6LLData *const tdata = &tdata_stack;
+    char                    sbuf1[sizeof(_nm_utils_to_string_buffer)];
+    int                     r;
+
+    _LOGD("test start (/l3-ipv6ll/%d)", TEST_IDX);
+
+    if (nmtst_test_quick()) {
+        gs_free char *msg =
+            g_strdup_printf("Skipping test: don't run long running test %s (NMTST_DEBUG=slow)\n",
+                            g_get_prgname() ?: "test-l3-ipv6ll");
+
+        g_test_skip(msg);
+        return;
+    }
+
+    tdata->f = _test_fixture_1_setup(&test_fixture, TEST_IDX);
+
+    if (NM_IN_SET(tdata->f->test_idx, 4)) {
+        _LOGD("add conflicting IPv6LL on other interface...");
+        r = nm_platform_link_change_flags(tdata->f->platform, tdata->f->ifindex1, IFF_UP, FALSE);
+        g_assert_cmpint(r, >=, 0);
+
+        r = nm_platform_link_set_inet6_addr_gen_mode(tdata->f->platform,
+                                                     tdata->f->ifindex1,
+                                                     NM_IN6_ADDR_GEN_MODE_NONE);
+        g_assert_cmpint(r, >=, 0);
+
+        r = nm_platform_link_change_flags(tdata->f->platform, tdata->f->ifindex1, IFF_UP, TRUE);
+        g_assert_cmpint(r, >=, 0);
+
+        nmtstp_ip6_address_add(tdata->f->platform,
+                               -1,
+                               tdata->f->ifindex1,
+                               *nmtst_inet6_from_string(_LLADDR_TEST1),
+                               64,
+                               in6addr_any,
+                               NM_PLATFORM_LIFETIME_PERMANENT,
+                               NM_PLATFORM_LIFETIME_PERMANENT,
+                               0);
+
+        _LOGD("wait for IPv6 LL address...");
+        tdata->lladdr0 =
+            nmp_object_ref(_test_l3_ipv6ll_find_lladdr_wait(tdata, tdata->f->ifindex1));
+    } else if (NM_IN_SET(tdata->f->test_idx, 2, 3)) {
+        _LOGD("wait for IPv6 LL address...");
+        tdata->lladdr0 =
+            nmp_object_ref(_test_l3_ipv6ll_find_lladdr_wait(tdata, tdata->f->ifindex0));
+    }
+
+    if (tdata->lladdr0) {
+        _LOGD("got IPv6 LL address %s",
+              nmp_object_to_string(tdata->lladdr0,
+                                   NMP_OBJECT_TO_STRING_PUBLIC,
+                                   sbuf1,
+                                   sizeof(sbuf1)));
+    }
+
+    l3cfg0        = _netns_access_l3cfg(tdata->f->netns, tdata->f->ifindex0);
+    tdata->l3cfg0 = l3cfg0;
+
+    g_signal_connect(tdata->l3cfg0,
+                     NM_L3CFG_SIGNAL_NOTIFY,
+                     G_CALLBACK(_test_l3_ipv6ll_signal_notify),
+                     tdata);
+
+    tdata->l3ipv6ll = nm_l3_ipv6ll_new_stable_privacy(tdata->l3cfg0,
+                                                      NM_IN_SET(tdata->f->test_idx, 3),
+                                                      NM_UTILS_STABLE_TYPE_UUID,
+                                                      tdata->f->ifname0,
+                                                      "b6a5b934-c649-43dc-a524-3dfdb74f9419",
+                                                      _test_l3_ipv6ll_callback_changed,
+                                                      tdata);
+
+    g_assert(nm_l3_ipv6ll_get_l3cfg(tdata->l3ipv6ll) == tdata->l3cfg0);
+    g_assert_cmpint(nm_l3_ipv6ll_get_ifindex(tdata->l3ipv6ll), ==, tdata->f->ifindex0);
+
+    tdata->step = 1;
+    nmtst_main_context_iterate_until_assert(NULL, 7000, tdata->steps_done);
+
+    g_assert_cmpint(tdata->step, ==, 1);
+    if (NM_IN_SET(tdata->f->test_idx, 3))
+        g_assert_cmpint(tdata->ipv6ll_callback_step, ==, 1);
+    else if (NM_IN_SET(tdata->f->test_idx, 4))
+        g_assert_cmpint(tdata->ipv6ll_callback_step, ==, 3);
+    else
+        g_assert_cmpint(tdata->ipv6ll_callback_step, ==, 2);
+    g_assert(tdata->steps_done);
+
+    tdata->step = 2;
+    nmtst_main_context_iterate_until(NULL, nmtst_get_rand_uint32() % 1000, FALSE);
+
+    g_assert_cmpint(tdata->step, ==, 2);
+    if (NM_IN_SET(tdata->f->test_idx, 3))
+        g_assert_cmpint(tdata->ipv6ll_callback_step, ==, 1);
+    else if (NM_IN_SET(tdata->f->test_idx, 4))
+        g_assert_cmpint(tdata->ipv6ll_callback_step, ==, 3);
+    else
+        g_assert_cmpint(tdata->ipv6ll_callback_step, ==, 2);
+    g_assert(tdata->steps_done);
+    g_assert(tdata->steps_done);
+
+    tdata->step       = 0;
+    tdata->steps_done = FALSE;
+
+    g_signal_handlers_disconnect_by_func(tdata->l3cfg0,
+                                         G_CALLBACK(_test_l3_ipv6ll_signal_notify),
+                                         tdata);
+
+    nm_l3_ipv6ll_destroy(tdata->l3ipv6ll);
+
+    nm_clear_nmp_object(&tdata->lladdr0);
+}
+
+/*****************************************************************************/
+
 NMTstpSetupFunc const _nmtstp_setup_platform_func = nm_linux_platform_setup;
 
 void
@@ -798,4 +1087,8 @@ _nmtstp_setup_tests(void)
     g_test_add_data_func("/l3cfg/4", GINT_TO_POINTER(4), test_l3cfg);
     g_test_add_data_func("/l3-ipv4ll/1", GINT_TO_POINTER(1), test_l3_ipv4ll);
     g_test_add_data_func("/l3-ipv4ll/2", GINT_TO_POINTER(2), test_l3_ipv4ll);
+    g_test_add_data_func("/l3-ipv6ll/1", GINT_TO_POINTER(1), test_l3_ipv6ll);
+    g_test_add_data_func("/l3-ipv6ll/2", GINT_TO_POINTER(2), test_l3_ipv6ll);
+    g_test_add_data_func("/l3-ipv6ll/3", GINT_TO_POINTER(3), test_l3_ipv6ll);
+    g_test_add_data_func("/l3-ipv6ll/4", GINT_TO_POINTER(4), test_l3_ipv6ll);
 }
diff --git a/src/core/tests/test-systemd.c b/src/core/tests/test-systemd.c
index 12d2b911..be070248 100644
--- a/src/core/tests/test-systemd.c
+++ b/src/core/tests/test-systemd.c
@@ -36,14 +36,14 @@ test_dhcp_create(void)
 static void
 test_lldp_create(void)
 {
-    sd_lldp *lldp = NULL;
-    int      r;
+    sd_lldp_rx *lldp = NULL;
+    int         r;
 
-    r = sd_lldp_new(&lldp);
+    r = sd_lldp_rx_new(&lldp);
     g_assert(r == 0);
     g_assert(lldp);
 
-    sd_lldp_unref(lldp);
+    sd_lldp_rx_unref(lldp);
 }
 
 /*****************************************************************************/
diff --git a/src/core/tests/test-utils.c b/src/core/tests/test-utils.c
index 1d562bde..59d5fd53 100644
--- a/src/core/tests/test-utils.c
+++ b/src/core/tests/test-utils.c
@@ -16,60 +16,55 @@ test_stable_privacy(void)
     struct in6_addr addr1;
 
     inet_pton(AF_INET6, "1234::", &addr1);
-    nm_utils_ipv6_addr_set_stable_privacy_impl(NM_UTILS_STABLE_TYPE_UUID,
-                                               &addr1,
-                                               "eth666",
-                                               "6b138152-9f3e-4b97-aaf7-e6e553f2a24e",
-                                               0,
-                                               (guint8 *) "key",
-                                               3,
-                                               NULL);
+    nm_utils_ipv6_addr_set_stable_privacy_with_host_id(NM_UTILS_STABLE_TYPE_UUID,
+                                                       &addr1,
+                                                       "eth666",
+                                                       "6b138152-9f3e-4b97-aaf7-e6e553f2a24e",
+                                                       0,
+                                                       (guint8 *) "key",
+                                                       3);
     nmtst_assert_ip6_address(&addr1, "1234::4ceb:14cd:3d54:793f");
 
     /* We get an address without the UUID. */
     inet_pton(AF_INET6, "1::", &addr1);
-    nm_utils_ipv6_addr_set_stable_privacy_impl(NM_UTILS_STABLE_TYPE_UUID,
-                                               &addr1,
-                                               "eth666",
-                                               "",
-                                               384,
-                                               (guint8 *) "key",
-                                               3,
-                                               NULL);
+    nm_utils_ipv6_addr_set_stable_privacy_with_host_id(NM_UTILS_STABLE_TYPE_UUID,
+                                                       &addr1,
+                                                       "eth666",
+                                                       "",
+                                                       384,
+                                                       (guint8 *) "key",
+                                                       3);
     nmtst_assert_ip6_address(&addr1, "1::11aa:2530:9144:dafa");
 
     /* We get a different address in a different network. */
     inet_pton(AF_INET6, "2::", &addr1);
-    nm_utils_ipv6_addr_set_stable_privacy_impl(NM_UTILS_STABLE_TYPE_UUID,
-                                               &addr1,
-                                               "eth666",
-                                               "",
-                                               384,
-                                               (guint8 *) "key",
-                                               3,
-                                               NULL);
+    nm_utils_ipv6_addr_set_stable_privacy_with_host_id(NM_UTILS_STABLE_TYPE_UUID,
+                                                       &addr1,
+                                                       "eth666",
+                                                       "",
+                                                       384,
+                                                       (guint8 *) "key",
+                                                       3);
     nmtst_assert_ip6_address(&addr1, "2::338e:8d:c11:8726");
 
     inet_pton(AF_INET6, "1234::", &addr1);
-    nm_utils_ipv6_addr_set_stable_privacy_impl(NM_UTILS_STABLE_TYPE_STABLE_ID,
-                                               &addr1,
-                                               "eth666",
-                                               "6b138152-9f3e-4b97-aaf7-e6e553f2a24e",
-                                               0,
-                                               (guint8 *) "key",
-                                               3,
-                                               NULL);
+    nm_utils_ipv6_addr_set_stable_privacy_with_host_id(NM_UTILS_STABLE_TYPE_STABLE_ID,
+                                                       &addr1,
+                                                       "eth666",
+                                                       "6b138152-9f3e-4b97-aaf7-e6e553f2a24e",
+                                                       0,
+                                                       (guint8 *) "key",
+                                                       3);
     nmtst_assert_ip6_address(&addr1, "1234::ad4c:ae44:3d30:af1e");
 
     inet_pton(AF_INET6, "1234::", &addr1);
-    nm_utils_ipv6_addr_set_stable_privacy_impl(NM_UTILS_STABLE_TYPE_STABLE_ID,
-                                               &addr1,
-                                               "eth666",
-                                               "stable-id-1",
-                                               0,
-                                               (guint8 *) "key",
-                                               3,
-                                               NULL);
+    nm_utils_ipv6_addr_set_stable_privacy_with_host_id(NM_UTILS_STABLE_TYPE_STABLE_ID,
+                                                       &addr1,
+                                                       "eth666",
+                                                       "stable-id-1",
+                                                       0,
+                                                       (guint8 *) "key",
+                                                       3);
     nmtst_assert_ip6_address(&addr1, "1234::4944:67b0:7a6c:1cf");
 }