chiark / gitweb /
sd-rtnl: make joining broadcast groups implicit
authorTom Gundersen <teg@jklm.no>
Thu, 11 Jun 2015 13:55:37 +0000 (15:55 +0200)
committerSven Eden <yamakuzure@gmx.net>
Tue, 14 Mar 2017 09:01:51 +0000 (10:01 +0100)
src/libelogind/sd-rtnl/local-addresses.c
src/libelogind/sd-rtnl/rtnl-util.c
src/libelogind/sd-rtnl/sd-rtnl.c
src/libelogind/sd-rtnl/test-rtnl.c
src/systemd/sd-rtnl.h

index 31bfa06..f05cbf1 100644 (file)
@@ -66,7 +66,7 @@ int local_addresses(sd_rtnl *context, int ifindex, int af, struct local_address
         if (context)
                 rtnl = sd_rtnl_ref(context);
         else {
-                r = sd_rtnl_open(&rtnl, 0);
+                r = sd_rtnl_open(&rtnl);
                 if (r < 0)
                         return r;
         }
@@ -177,7 +177,7 @@ int local_gateways(sd_rtnl *context, int ifindex, int af, struct local_address *
         if (context)
                 rtnl = sd_rtnl_ref(context);
         else {
-                r = sd_rtnl_open(&rtnl, 0);
+                r = sd_rtnl_open(&rtnl);
                 if (r < 0)
                         return r;
         }
index 9ddf074..c2b1a5c 100644 (file)
@@ -34,7 +34,7 @@ int rtnl_set_link_name(sd_rtnl **rtnl, int ifindex, const char *name) {
         assert(name);
 
         if (!*rtnl) {
-                r = sd_rtnl_open(rtnl, 0);
+                r = sd_rtnl_open(rtnl);
                 if (r < 0)
                         return r;
         }
@@ -66,7 +66,7 @@ int rtnl_set_link_properties(sd_rtnl **rtnl, int ifindex, const char *alias,
                 return 0;
 
         if (!*rtnl) {
-                r = sd_rtnl_open(rtnl, 0);
+                r = sd_rtnl_open(rtnl);
                 if (r < 0)
                         return r;
         }
index 40dea12..c682007 100644 (file)
@@ -106,25 +106,7 @@ static bool rtnl_pid_changed(sd_rtnl *rtnl) {
         return rtnl->original_pid != getpid();
 }
 
-static int rtnl_compute_groups_ap(uint32_t *_groups, unsigned n_groups, va_list ap) {
-        uint32_t groups = 0;
-        unsigned i;
-
-        for (i = 0; i < n_groups; i++) {
-                unsigned group;
-
-                group = va_arg(ap, unsigned);
-                assert_return(group < 32, -EINVAL);
-
-                groups |= group ? (1 << (group - 1)) : 0;
-        }
-
-        *_groups = groups;
-
-        return 0;
-}
-
-static int rtnl_open_fd_ap(sd_rtnl **ret, int fd, unsigned n_groups, va_list ap) {
+int sd_rtnl_open_fd(sd_rtnl **ret, int fd) {
         _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
         socklen_t addrlen;
         int r, one = 1;
@@ -144,10 +126,6 @@ static int rtnl_open_fd_ap(sd_rtnl **ret, int fd, unsigned n_groups, va_list ap)
         if (r < 0)
                 return -errno;
 
-        r = rtnl_compute_groups_ap(&rtnl->sockaddr.nl.nl_groups, n_groups, ap);
-        if (r < 0)
-                return r;
-
         addrlen = sizeof(rtnl->sockaddr);
 
         r = bind(fd, &rtnl->sockaddr.sa, addrlen);
@@ -167,33 +145,33 @@ static int rtnl_open_fd_ap(sd_rtnl **ret, int fd, unsigned n_groups, va_list ap)
         return 0;
 }
 
-int sd_rtnl_open_fd(sd_rtnl **ret, int fd, unsigned n_groups, ...) {
-        va_list ap;
+int sd_rtnl_open(sd_rtnl **ret) {
+        _cleanup_close_ int fd = -1;
         int r;
 
-        va_start(ap, n_groups);
-        r = rtnl_open_fd_ap(ret, fd, n_groups, ap);
-        va_end(ap);
-
-        return r;
-}
-
-int sd_rtnl_open(sd_rtnl **ret, unsigned n_groups, ...) {
-        va_list ap;
-        int fd, r;
-
         fd = socket(PF_NETLINK, SOCK_RAW|SOCK_CLOEXEC|SOCK_NONBLOCK, NETLINK_ROUTE);
         if (fd < 0)
                 return -errno;
 
-        va_start(ap, n_groups);
-        r = rtnl_open_fd_ap(ret, fd, n_groups, ap);
-        va_end(ap);
-
-        if (r < 0) {
-                safe_close(fd);
+        r = sd_rtnl_open_fd(ret, fd);
+        if (r < 0)
                 return r;
-        }
+
+        fd = -1;
+
+        return 0;
+}
+
+static int rtnl_join_broadcast_group(sd_rtnl *rtnl, unsigned group) {
+        int r;
+
+        assert(rtnl);
+        assert(rtnl->fd >= 0);
+        assert(group > 0);
+
+        r = setsockopt(rtnl->fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, &group, sizeof(group));
+        if (r < 0)
+                return -errno;
 
         return 0;
 }
@@ -1005,14 +983,12 @@ int sd_rtnl_add_match(sd_rtnl *rtnl,
                       uint16_t type,
                       sd_rtnl_message_handler_t callback,
                       void *userdata) {
-        struct match_callback *c;
+        _cleanup_free_ struct match_callback *c = NULL;
+        int r;
 
         assert_return(rtnl, -EINVAL);
         assert_return(callback, -EINVAL);
         assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
-        assert_return(rtnl_message_type_is_link(type) ||
-                      rtnl_message_type_is_addr(type) ||
-                      rtnl_message_type_is_route(type), -EOPNOTSUPP);
 
         c = new0(struct match_callback, 1);
         if (!c)
@@ -1022,8 +998,36 @@ int sd_rtnl_add_match(sd_rtnl *rtnl,
         c->type = type;
         c->userdata = userdata;
 
+        switch (type) {
+                case RTM_NEWLINK:
+                case RTM_SETLINK:
+                case RTM_GETLINK:
+                case RTM_DELLINK:
+                        r = rtnl_join_broadcast_group(rtnl, RTNLGRP_LINK);
+                        if (r < 0)
+                                return r;
+
+                        break;
+                case RTM_NEWADDR:
+                case RTM_GETADDR:
+                case RTM_DELADDR:
+                        r = rtnl_join_broadcast_group(rtnl, RTNLGRP_IPV4_IFADDR);
+                        if (r < 0)
+                                return r;
+
+                        r = rtnl_join_broadcast_group(rtnl, RTNLGRP_IPV6_IFADDR);
+                        if (r < 0)
+                                return r;
+
+                        break;
+                default:
+                        return -EOPNOTSUPP;
+        }
+
         LIST_PREPEND(match_callbacks, rtnl->match_callbacks, c);
 
+        c = NULL;
+
         return 0;
 }
 
@@ -1037,6 +1041,13 @@ int sd_rtnl_remove_match(sd_rtnl *rtnl,
         assert_return(callback, -EINVAL);
         assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
 
+        /* we should unsubscribe from the broadcast groups at this point, but it is not so
+           trivial for a few reasons: the refcounting is a bit of a mess and not obvious
+           how it will look like after we add genetlink support, and it is also not possible
+           to query what broadcast groups were subscribed to when we inherit the socket to get
+           the initial refcount. The latter could indeed be done for the first 32 broadcast
+           groups (which incidentally is all we currently support in .socket units anyway),
+           but we better not rely on only ever using 32 groups. */
         LIST_FOREACH(match_callbacks, c, rtnl->match_callbacks)
                 if (c->callback == callback && c->type == type && c->userdata == userdata) {
                         LIST_REMOVE(match_callbacks, rtnl->match_callbacks, c);
index 47cce64..94b1cb7 100644 (file)
@@ -184,8 +184,8 @@ static void test_route(void) {
 static void test_multiple(void) {
         sd_rtnl *rtnl1, *rtnl2;
 
-        assert_se(sd_rtnl_open(&rtnl1, 0) >= 0);
-        assert_se(sd_rtnl_open(&rtnl2, 0) >= 0);
+        assert_se(sd_rtnl_open(&rtnl1) >= 0);
+        assert_se(sd_rtnl_open(&rtnl2) >= 0);
 
         rtnl1 = sd_rtnl_unref(rtnl1);
         rtnl2 = sd_rtnl_unref(rtnl2);
@@ -216,7 +216,7 @@ static void test_event_loop(int ifindex) {
         ifname = strdup("lo2");
         assert_se(ifname);
 
-        assert_se(sd_rtnl_open(&rtnl, 0) >= 0);
+        assert_se(sd_rtnl_open(&rtnl) >= 0);
         assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_GETLINK, ifindex) >= 0);
 
         assert_se(sd_rtnl_call_async(rtnl, m, &link_handler, ifname, 0, NULL) >= 0);
@@ -256,7 +256,7 @@ static void test_async(int ifindex) {
         ifname = strdup("lo");
         assert_se(ifname);
 
-        assert_se(sd_rtnl_open(&rtnl, 0) >= 0);
+        assert_se(sd_rtnl_open(&rtnl) >= 0);
 
         assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_GETLINK, ifindex) >= 0);
 
@@ -273,7 +273,7 @@ static void test_pipe(int ifindex) {
         _cleanup_rtnl_message_unref_ sd_rtnl_message *m1 = NULL, *m2 = NULL;
         int counter = 0;
 
-        assert_se(sd_rtnl_open(&rtnl, 0) >= 0);
+        assert_se(sd_rtnl_open(&rtnl) >= 0);
 
         assert_se(sd_rtnl_message_new_link(rtnl, &m1, RTM_GETLINK, ifindex) >= 0);
         assert_se(sd_rtnl_message_new_link(rtnl, &m2, RTM_GETLINK, ifindex) >= 0);
@@ -330,7 +330,7 @@ static void test_container(void) {
 static void test_match(void) {
         _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
 
-        assert_se(sd_rtnl_open(&rtnl, 0) >= 0);
+        assert_se(sd_rtnl_open(&rtnl) >= 0);
 
         assert_se(sd_rtnl_add_match(rtnl, RTM_NEWLINK, &link_handler, NULL) >= 0);
         assert_se(sd_rtnl_add_match(rtnl, RTM_NEWLINK, &link_handler, NULL) >= 0);
@@ -395,7 +395,7 @@ int main(void) {
 
         test_container();
 
-        assert_se(sd_rtnl_open(&rtnl, 0) >= 0);
+        assert_se(sd_rtnl_open(&rtnl) >= 0);
         assert_se(rtnl);
 
         if_loopback = (int) if_nametoindex("lo");
index be318e5..b05690c 100644 (file)
@@ -42,8 +42,8 @@ typedef int (*sd_rtnl_message_handler_t)(sd_rtnl *rtnl, sd_rtnl_message *m, void
 
 /* bus */
 int sd_rtnl_new_from_netlink(sd_rtnl **nl, int fd);
-int sd_rtnl_open(sd_rtnl **nl, unsigned n_groups, ...);
-int sd_rtnl_open_fd(sd_rtnl **nl, int fd, unsigned n_groups, ...);
+int sd_rtnl_open(sd_rtnl **nl);
+int sd_rtnl_open_fd(sd_rtnl **nl, int fd);
 int sd_rtnl_inc_rcvbuf(const sd_rtnl *const rtnl, const int size);
 
 sd_rtnl *sd_rtnl_ref(sd_rtnl *nl);
@@ -57,7 +57,6 @@ int sd_rtnl_call_async_cancel(sd_rtnl *nl, uint32_t serial);
 int sd_rtnl_call(sd_rtnl *nl, sd_rtnl_message *message, uint64_t timeout,
                  sd_rtnl_message **reply);
 
-
 int sd_rtnl_get_events(sd_rtnl *nl);
 int sd_rtnl_get_timeout(sd_rtnl *nl, uint64_t *timeout);
 int sd_rtnl_process(sd_rtnl *nl, sd_rtnl_message **ret);