]> git.proxmox.com Git - systemd.git/blobdiff - src/libsystemd/sd-netlink/test-netlink.c
New upstream version 240
[systemd.git] / src / libsystemd / sd-netlink / test-netlink.c
index 03773fb936141a02690db756443eac77c7828867..b13fa224cc4c06a94f772d4ea185e35dedcbd942 100644 (file)
@@ -5,6 +5,7 @@
 
 #include "sd-netlink.h"
 
+#include "alloc-util.h"
 #include "ether-addr-util.h"
 #include "macro.h"
 #include "missing.h"
@@ -177,8 +178,9 @@ static int link_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata)
 
         assert_se(rtnl);
         assert_se(m);
+        assert_se(userdata);
 
-        log_info("got link info about %s", ifname);
+        log_info("%s: got link info about %s", __func__, ifname);
         free(ifname);
 
         assert_se(sd_netlink_message_read_string(m, IFLA_IFNAME, &data) >= 0);
@@ -199,7 +201,7 @@ static void test_event_loop(int ifindex) {
         assert_se(sd_netlink_open(&rtnl) >= 0);
         assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_GETLINK, ifindex) >= 0);
 
-        assert_se(sd_netlink_call_async(rtnl, m, link_handler, ifname, 0, NULL) >= 0);
+        assert_se(sd_netlink_call_async(rtnl, NULL, m, link_handler, NULL, ifname, 0, NULL) >= 0);
 
         assert_se(sd_event_default(&event) >= 0);
 
@@ -212,25 +214,46 @@ static void test_event_loop(int ifindex) {
         assert_se((rtnl = sd_netlink_unref(rtnl)) == NULL);
 }
 
-static int pipe_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
-        int *counter = userdata;
-        int r;
+static void test_async_destroy(void *userdata) {
+}
 
-        (*counter)--;
+static void test_async(int ifindex) {
+        _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
+        _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL, *r = NULL;
+        _cleanup_(sd_netlink_slot_unrefp) sd_netlink_slot *slot = NULL;
+        sd_netlink_destroy_t destroy_callback;
+        const char *description;
+        char *ifname;
 
-        r = sd_netlink_message_get_errno(m);
+        ifname = strdup("lo");
+        assert_se(ifname);
 
-        log_info_errno(r, "%d left in pipe. got reply: %m", *counter);
+        assert_se(sd_netlink_open(&rtnl) >= 0);
 
-        assert_se(r >= 0);
+        assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_GETLINK, ifindex) >= 0);
 
-        return 1;
+        assert_se(sd_netlink_call_async(rtnl, &slot, m, link_handler, test_async_destroy, ifname, 0, "hogehoge") >= 0);
+
+        assert_se(sd_netlink_slot_get_netlink(slot) == rtnl);
+        assert_se(sd_netlink_slot_get_userdata(slot) == ifname);
+        assert_se(sd_netlink_slot_get_destroy_callback(slot, &destroy_callback) == 1);
+        assert_se(destroy_callback == test_async_destroy);
+        assert_se(sd_netlink_slot_get_floating(slot) == 0);
+        assert_se(sd_netlink_slot_get_description(slot, &description) == 1);
+        assert_se(streq(description, "hogehoge"));
+
+        assert_se(sd_netlink_wait(rtnl, 0) >= 0);
+        assert_se(sd_netlink_process(rtnl, &r) >= 0);
+
+        assert_se((rtnl = sd_netlink_unref(rtnl)) == NULL);
 }
 
-static void test_async(int ifindex) {
+static void test_slot_set(int ifindex) {
         _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
         _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL, *r = NULL;
-        uint32_t serial;
+        _cleanup_(sd_netlink_slot_unrefp) sd_netlink_slot *slot = NULL;
+        sd_netlink_destroy_t destroy_callback;
+        const char *description;
         char *ifname;
 
         ifname = strdup("lo");
@@ -240,7 +263,23 @@ static void test_async(int ifindex) {
 
         assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_GETLINK, ifindex) >= 0);
 
-        assert_se(sd_netlink_call_async(rtnl, m, link_handler, ifname, 0, &serial) >= 0);
+        assert_se(sd_netlink_call_async(rtnl, &slot, m, link_handler, NULL, NULL, 0, NULL) >= 0);
+
+        assert_se(sd_netlink_slot_get_netlink(slot) == rtnl);
+        assert_se(!sd_netlink_slot_get_userdata(slot));
+        assert_se(!sd_netlink_slot_set_userdata(slot, ifname));
+        assert_se(sd_netlink_slot_get_userdata(slot) == ifname);
+        assert_se(sd_netlink_slot_get_destroy_callback(slot, NULL) == 0);
+        assert_se(sd_netlink_slot_set_destroy_callback(slot, test_async_destroy) >= 0);
+        assert_se(sd_netlink_slot_get_destroy_callback(slot, &destroy_callback) == 1);
+        assert_se(destroy_callback == test_async_destroy);
+        assert_se(sd_netlink_slot_get_floating(slot) == 0);
+        assert_se(sd_netlink_slot_set_floating(slot, 1) == 1);
+        assert_se(sd_netlink_slot_get_floating(slot) == 1);
+        assert_se(sd_netlink_slot_get_description(slot, NULL) == 0);
+        assert_se(sd_netlink_slot_set_description(slot, "hogehoge") >= 0);
+        assert_se(sd_netlink_slot_get_description(slot, &description) == 1);
+        assert_se(streq(description, "hogehoge"));
 
         assert_se(sd_netlink_wait(rtnl, 0) >= 0);
         assert_se(sd_netlink_process(rtnl, &r) >= 0);
@@ -248,6 +287,116 @@ static void test_async(int ifindex) {
         assert_se((rtnl = sd_netlink_unref(rtnl)) == NULL);
 }
 
+struct test_async_object {
+        unsigned n_ref;
+        char *ifname;
+};
+
+static struct test_async_object *test_async_object_free(struct test_async_object *t) {
+        assert(t);
+
+        free(t->ifname);
+        return mfree(t);
+}
+
+DEFINE_PRIVATE_TRIVIAL_REF_UNREF_FUNC(struct test_async_object, test_async_object, test_async_object_free);
+DEFINE_TRIVIAL_CLEANUP_FUNC(struct test_async_object *, test_async_object_unref);
+
+static int link_handler2(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
+        struct test_async_object *t = userdata;
+        const char *data;
+
+        assert_se(rtnl);
+        assert_se(m);
+        assert_se(userdata);
+
+        log_info("%s: got link info about %s", __func__, t->ifname);
+
+        assert_se(sd_netlink_message_read_string(m, IFLA_IFNAME, &data) >= 0);
+        assert_se(streq(data, "lo"));
+
+        return 1;
+}
+
+static void test_async_object_destroy(void *userdata) {
+        struct test_async_object *t = userdata;
+
+        assert(userdata);
+
+        log_info("%s: n_ref=%u", __func__, t->n_ref);
+        test_async_object_unref(t);
+}
+
+static void test_async_destroy_callback(int ifindex) {
+        _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
+        _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL, *r = NULL;
+        _cleanup_(test_async_object_unrefp) struct test_async_object *t = NULL;
+        _cleanup_(sd_netlink_slot_unrefp) sd_netlink_slot *slot = NULL;
+        char *ifname;
+
+        assert_se(t = new(struct test_async_object, 1));
+        assert_se(ifname = strdup("lo"));
+        *t = (struct test_async_object) {
+                .n_ref = 1,
+                .ifname = ifname,
+        };
+
+        assert_se(sd_netlink_open(&rtnl) >= 0);
+
+        /* destroy callback is called after processing message */
+        assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_GETLINK, ifindex) >= 0);
+        assert_se(sd_netlink_call_async(rtnl, NULL, m, link_handler2, test_async_object_destroy, t, 0, NULL) >= 0);
+
+        assert_se(t->n_ref == 1);
+        assert_se(test_async_object_ref(t));
+        assert_se(t->n_ref == 2);
+
+        assert_se(sd_netlink_wait(rtnl, 0) >= 0);
+        assert_se(sd_netlink_process(rtnl, &r) == 1);
+        assert_se(t->n_ref == 1);
+
+        assert_se(!sd_netlink_message_unref(m));
+
+        /* destroy callback is called when asynchronous call is cancelled, that is, slot is freed. */
+        assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_GETLINK, ifindex) >= 0);
+        assert_se(sd_netlink_call_async(rtnl, &slot, m, link_handler2, test_async_object_destroy, t, 0, NULL) >= 0);
+
+        assert_se(t->n_ref == 1);
+        assert_se(test_async_object_ref(t));
+        assert_se(t->n_ref == 2);
+
+        assert_se(!(slot = sd_netlink_slot_unref(slot)));
+        assert_se(t->n_ref == 1);
+
+        assert_se(!sd_netlink_message_unref(m));
+
+        /* destroy callback is also called by sd_netlink_unref() */
+        assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_GETLINK, ifindex) >= 0);
+        assert_se(sd_netlink_call_async(rtnl, NULL, m, link_handler2, test_async_object_destroy, t, 0, NULL) >= 0);
+
+        assert_se(t->n_ref == 1);
+        assert_se(test_async_object_ref(t));
+        assert_se(t->n_ref == 2);
+
+        assert_se((rtnl = sd_netlink_unref(rtnl)) == NULL);
+        assert_se(t->n_ref == 1);
+}
+
+static int pipe_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
+        int *counter = userdata;
+        int r;
+
+        (*counter)--;
+
+        r = sd_netlink_message_get_errno(m);
+
+        log_info_errno(r, "%d left in pipe. got reply: %m", *counter);
+
+        assert_se(r >= 0);
+
+        return 1;
+}
+
 static void test_pipe(int ifindex) {
         _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
         _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m1 = NULL, *m2 = NULL;
@@ -259,10 +408,10 @@ static void test_pipe(int ifindex) {
         assert_se(sd_rtnl_message_new_link(rtnl, &m2, RTM_GETLINK, ifindex) >= 0);
 
         counter++;
-        assert_se(sd_netlink_call_async(rtnl, m1, pipe_handler, &counter, 0, NULL) >= 0);
+        assert_se(sd_netlink_call_async(rtnl, NULL, m1, pipe_handler, NULL, &counter, 0, NULL) >= 0);
 
         counter++;
-        assert_se(sd_netlink_call_async(rtnl, m2, pipe_handler, &counter, 0, NULL) >= 0);
+        assert_se(sd_netlink_call_async(rtnl, NULL, m2, pipe_handler, NULL, &counter, 0, NULL) >= 0);
 
         while (counter > 0) {
                 assert_se(sd_netlink_wait(rtnl, 0) >= 0);
@@ -308,16 +457,17 @@ static void test_container(sd_netlink *rtnl) {
 }
 
 static void test_match(void) {
+        _cleanup_(sd_netlink_slot_unrefp) sd_netlink_slot *s1 = NULL, *s2 = NULL;
         _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
 
         assert_se(sd_netlink_open(&rtnl) >= 0);
 
-        assert_se(sd_netlink_add_match(rtnl, RTM_NEWLINK, link_handler, NULL) >= 0);
-        assert_se(sd_netlink_add_match(rtnl, RTM_NEWLINK, link_handler, NULL) >= 0);
+        assert_se(sd_netlink_add_match(rtnl, &s1, RTM_NEWLINK, link_handler, NULL, NULL, NULL) >= 0);
+        assert_se(sd_netlink_add_match(rtnl, &s2, RTM_NEWLINK, link_handler, NULL, NULL, NULL) >= 0);
+        assert_se(sd_netlink_add_match(rtnl, NULL, RTM_NEWLINK, link_handler, NULL, NULL, NULL) >= 0);
 
-        assert_se(sd_netlink_remove_match(rtnl, RTM_NEWLINK, link_handler, NULL) == 1);
-        assert_se(sd_netlink_remove_match(rtnl, RTM_NEWLINK, link_handler, NULL) == 1);
-        assert_se(sd_netlink_remove_match(rtnl, RTM_NEWLINK, link_handler, NULL) == 0);
+        assert_se(!(s1 = sd_netlink_slot_unref(s1)));
+        assert_se(!(s2 = sd_netlink_slot_unref(s2)));
 
         assert_se((rtnl = sd_netlink_unref(rtnl)) == NULL);
 }
@@ -366,31 +516,26 @@ int main(void) {
         uint16_t type;
 
         test_match();
-
         test_multiple();
 
         assert_se(sd_netlink_open(&rtnl) >= 0);
         assert_se(rtnl);
 
         test_route(rtnl);
-
         test_message(rtnl);
-
         test_container(rtnl);
 
         if_loopback = (int) if_nametoindex("lo");
         assert_se(if_loopback > 0);
 
         test_async(if_loopback);
-
+        test_slot_set(if_loopback);
+        test_async_destroy_callback(if_loopback);
         test_pipe(if_loopback);
-
         test_event_loop(if_loopback);
-
         test_link_configure(rtnl, if_loopback);
 
         test_get_addresses(rtnl);
-
         test_message_link_bridge(rtnl);
 
         assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_GETLINK, if_loopback) >= 0);