]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
sd-netlink: add generic netlink support
authorJörg Thalheim <joerg@thalheim.io>
Mon, 18 Dec 2017 14:17:06 +0000 (15:17 +0100)
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Tue, 9 Jan 2018 13:00:49 +0000 (14:00 +0100)
This also adds the ability to incorporate arrays into netlink messages
and to determine when a netlink message is too big, used by some generic
netlink protocols.

15 files changed:
src/libsystemd/meson.build
src/libsystemd/sd-netlink/generic-netlink.c [new file with mode: 0644]
src/libsystemd/sd-netlink/netlink-internal.h
src/libsystemd/sd-netlink/netlink-message.c
src/libsystemd/sd-netlink/netlink-socket.c
src/libsystemd/sd-netlink/netlink-types.c
src/libsystemd/sd-netlink/netlink-types.h
src/libsystemd/sd-netlink/netlink-util.c
src/libsystemd/sd-netlink/netlink-util.h
src/libsystemd/sd-netlink/sd-netlink.c
src/libsystemd/sd-netlink/test-netlink.c
src/network/netdev/netdev.c
src/network/networkd-manager.c
src/network/networkd-manager.h
src/systemd/sd-netlink.h

index 4abf50b1113ff58aff989827e406160651af6fdd..9172116ef1e4ecc25febac601b198d1748177a67 100644 (file)
@@ -74,6 +74,7 @@ libsystemd_internal_sources = files('''
         sd-id128/id128-util.c
         sd-id128/id128-util.h
         sd-id128/sd-id128.c
+        sd-netlink/generic-netlink.c
         sd-netlink/local-addresses.c
         sd-netlink/local-addresses.h
         sd-netlink/netlink-internal.h
diff --git a/src/libsystemd/sd-netlink/generic-netlink.c b/src/libsystemd/sd-netlink/generic-netlink.c
new file mode 100644 (file)
index 0000000..e6e0f95
--- /dev/null
@@ -0,0 +1,96 @@
+#include <linux/genetlink.h>
+
+#include "sd-netlink.h"
+#include "netlink-internal.h"
+#include "alloc-util.h"
+
+typedef struct {
+        const char* name;
+        uint8_t version;
+} genl_family;
+
+static const genl_family genl_families[] = {
+        [SD_GENL_ID_CTRL] = { .name = "", .version = 1 },
+};
+
+int sd_genl_socket_open(sd_netlink **ret) {
+        return netlink_open_family(ret, NETLINK_GENERIC);
+}
+static int lookup_id(sd_netlink *nl, sd_genl_family family, uint16_t *id);
+
+static int genl_message_new(sd_netlink *nl, sd_genl_family family, uint16_t nlmsg_type, uint8_t cmd, sd_netlink_message **ret) {
+        int r;
+        struct genlmsghdr *genl;
+        const NLType *genl_cmd_type, *nl_type;
+        const NLTypeSystem *type_system;
+        size_t size;
+        _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
+
+        assert_return(nl->protocol == NETLINK_GENERIC, -EINVAL);
+
+        r = type_system_get_type(&genl_family_type_system_root, &genl_cmd_type, family);
+        if (r < 0)
+                return r;
+
+        r = message_new_empty(nl, &m);
+        if (r < 0)
+                return r;
+
+        size = NLMSG_SPACE(sizeof(struct genlmsghdr));
+        m->hdr = malloc0(size);
+        if (!m->hdr)
+                return -ENOMEM;
+
+        m->hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
+
+        type_get_type_system(genl_cmd_type, &type_system);
+
+        r = type_system_get_type(type_system, &nl_type, cmd);
+        if (r < 0)
+                return r;
+
+        m->hdr->nlmsg_len = size;
+        m->hdr->nlmsg_type = nlmsg_type;
+
+        type_get_type_system(nl_type, &m->containers[0].type_system);
+        genl = NLMSG_DATA(m->hdr);
+        genl->cmd = cmd;
+        genl->version = genl_families[family].version;
+
+        *ret = m;
+        m = NULL;
+
+        return 0;
+}
+
+int sd_genl_message_new(sd_netlink *nl, sd_genl_family family, uint8_t cmd, sd_netlink_message **ret) {
+        int r;
+        uint16_t id = GENL_ID_CTRL;
+
+        if (family != SD_GENL_ID_CTRL) {
+                r = lookup_id(nl, family, &id);
+                if (r < 0)
+                        return r;
+        }
+
+        return genl_message_new(nl, family, id, cmd, ret);
+}
+
+static int lookup_id(sd_netlink *nl, sd_genl_family family, uint16_t *id) {
+        int r;
+        _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
+
+        r = sd_genl_message_new(nl, SD_GENL_ID_CTRL, CTRL_CMD_GETFAMILY, &req);
+        if (r < 0)
+                return r;
+
+        r = sd_netlink_message_append_string(req, CTRL_ATTR_FAMILY_NAME, genl_families[family].name);
+        if (r < 0)
+                return r;
+
+        r = sd_netlink_call(nl, req, 0, &reply);
+        if (r < 0)
+                return r;
+
+        return sd_netlink_message_read_u16(reply, CTRL_ATTR_FAMILY_ID, id);
+}
index f045ff67ca4df047dc1cc715f6ac69def60672f8..dc553d708cfc1d3473d8774b81c34010eb69e937 100644 (file)
@@ -62,6 +62,8 @@ struct sd_netlink {
                 struct sockaddr_nl nl;
         } sockaddr;
 
+        int protocol;
+
         Hashmap *broadcast_group_refs;
         bool broadcast_group_dont_leave:1; /* until we can rely on 4.2 */
 
@@ -111,6 +113,8 @@ struct sd_netlink_message {
 
         sd_netlink *rtnl;
 
+        int protocol;
+
         struct nlmsghdr *hdr;
         struct netlink_container containers[RTNL_CONTAINER_DEPTH];
         unsigned n_containers; /* number of containers */
@@ -123,6 +127,8 @@ struct sd_netlink_message {
 int message_new(sd_netlink *rtnl, sd_netlink_message **ret, uint16_t type);
 int message_new_empty(sd_netlink *rtnl, sd_netlink_message **ret);
 
+int netlink_open_family(sd_netlink **ret, int family);
+
 int socket_open(int family);
 int socket_bind(sd_netlink *nl);
 int socket_broadcast_group_ref(sd_netlink *nl, unsigned group);
index c88754540e7f9158b75e9545b8b73125ada801fe..f5042ab5aa4f794983de8764a82fd2ae4db900c1 100644 (file)
@@ -55,7 +55,7 @@ int message_new_empty(sd_netlink *rtnl, sd_netlink_message **ret) {
                 return -ENOMEM;
 
         m->n_ref = REFCNT_INIT;
-
+        m->protocol = rtnl->protocol;
         m->sealed = false;
 
         *ret = m;
@@ -66,10 +66,15 @@ int message_new_empty(sd_netlink *rtnl, sd_netlink_message **ret) {
 int message_new(sd_netlink *rtnl, sd_netlink_message **ret, uint16_t type) {
         _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
         const NLType *nl_type;
+        const NLTypeSystem *type_system_root;
         size_t size;
         int r;
 
-        r = type_system_get_type(&type_system_root, &nl_type, type);
+        assert_return(rtnl, -EINVAL);
+
+        type_system_root = type_system_get_root(rtnl->protocol);
+
+        r = type_system_get_type(type_system_root, &nl_type, type);
         if (r < 0)
                 return r;
 
@@ -186,6 +191,10 @@ static int add_rtattr(sd_netlink_message *m, unsigned short type, const void *da
         /* get the new message size (with padding at the end) */
         message_length = offset + RTA_ALIGN(rta_length);
 
+        /* buffer should be smaller than both one page or 8K to be accepted by the kernel */
+        if (message_length > MIN(page_size(), 8192UL))
+                return -ENOBUFS;
+
         /* realloc to fit the new attribute */
         new_hdr = realloc(m->hdr, message_length);
         if (!new_hdr)
@@ -490,7 +499,7 @@ int sd_netlink_message_open_container_union(sd_netlink_message *m, unsigned shor
         if (r < 0)
                 return r;
 
-        /* do we evere need non-null size */
+        /* do we ever need non-null size */
         r = add_rtattr(m, type | NLA_F_NESTED, NULL, 0);
         if (r < 0)
                 return r;
@@ -500,14 +509,53 @@ int sd_netlink_message_open_container_union(sd_netlink_message *m, unsigned shor
         return 0;
 }
 
-
 int sd_netlink_message_close_container(sd_netlink_message *m) {
         assert_return(m, -EINVAL);
         assert_return(!m->sealed, -EPERM);
         assert_return(m->n_containers > 0, -EINVAL);
 
         m->containers[m->n_containers].type_system = NULL;
+        m->containers[m->n_containers].offset = 0;
+        m->n_containers--;
+
+        return 0;
+}
+
+int sd_netlink_message_open_array(sd_netlink_message *m, uint16_t type) {
+        int r;
+
+        assert_return(m, -EINVAL);
+        assert_return(!m->sealed, -EPERM);
+        assert_return(m->n_containers > 0, -EINVAL);
+
+        r = add_rtattr(m, type | NLA_F_NESTED, NULL, 0);
+        if (r < 0)
+                return r;
+
+        m->containers[m->n_containers].offset = r;
+        m->n_containers++;
+        m->containers[m->n_containers].type_system = m->containers[m->n_containers - 1].type_system;
+
+        return 0;
+}
+
+int sd_netlink_message_cancel_array(sd_netlink_message *m) {
+        unsigned i;
+        uint32_t rta_len;
+
+        assert_return(m, -EINVAL);
+        assert_return(!m->sealed, -EPERM);
+        assert_return(m->n_containers > 1, -EINVAL);
+
+        rta_len = GET_CONTAINER(m, (m->n_containers - 1))->rta_len;
+
+        for (i = 0; i < m->n_containers; i++)
+                GET_CONTAINER(m, i)->rta_len -= rta_len;
+
+        m->hdr->nlmsg_len -= rta_len;
+
         m->n_containers--;
+        m->containers[m->n_containers].type_system = NULL;
 
         return 0;
 }
@@ -899,6 +947,7 @@ int sd_netlink_message_get_errno(sd_netlink_message *m) {
 
 int sd_netlink_message_rewind(sd_netlink_message *m) {
         const NLType *nl_type;
+        const NLTypeSystem *type_system_root;
         uint16_t type;
         size_t size;
         unsigned i;
@@ -910,6 +959,8 @@ int sd_netlink_message_rewind(sd_netlink_message *m) {
         if (!m->sealed)
                 rtnl_message_seal(m);
 
+        type_system_root = type_system_get_root(m->protocol);
+
         for (i = 1; i <= m->n_containers; i++)
                 m->containers[i].attributes = mfree(m->containers[i].attributes);
 
@@ -921,7 +972,7 @@ int sd_netlink_message_rewind(sd_netlink_message *m) {
 
         assert(m->hdr);
 
-        r = type_system_get_type(&type_system_root, &nl_type, m->hdr->nlmsg_type);
+        r = type_system_get_type(type_system_root, &nl_type, m->hdr->nlmsg_type);
         if (r < 0)
                 return r;
 
index 22be94382a79c9b3a39e0753f20154520598ab9d..d9784f60dcf0b0538bfe8bab907cd92fda5e370c 100644 (file)
@@ -330,11 +330,14 @@ int socket_read_message(sd_netlink *rtnl) {
         size_t len;
         int r;
         unsigned i = 0;
+        const NLTypeSystem *type_system_root;
 
         assert(rtnl);
         assert(rtnl->rbuffer);
         assert(rtnl->rbuffer_allocated >= sizeof(struct nlmsghdr));
 
+        type_system_root = type_system_get_root(rtnl->protocol);
+
         /* read nothing, just get the pending message size */
         r = socket_recv_message(rtnl->fd, &iov, NULL, true);
         if (r <= 0)
@@ -396,7 +399,8 @@ int socket_read_message(sd_netlink *rtnl) {
                 }
 
                 /* check that we support this message type */
-                r = type_system_get_type(&type_system_root, &nl_type, new_msg->nlmsg_type);
+                r = type_system_get_type(type_system_root, &nl_type, new_msg->nlmsg_type);
+
                 if (r < 0) {
                         if (r == -EOPNOTSUPP)
                                 log_debug("sd-netlink: ignored message with unknown type: %i",
index 7cc4a14446175711e383a01a0a9daf97e737db30..6dea62e313d673199979eed79b89fdb1cfc88aab 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/if_link.h>
 #include <linux/if_tunnel.h>
 #include <linux/fib_rules.h>
+#include <linux/genetlink.h>
 
 #if HAVE_VXCAN_INFO_PEER
 #include <linux/can/vxcan.h>
@@ -46,6 +47,7 @@
 #include "netlink-types.h"
 #include "string-table.h"
 #include "util.h"
+#include "sd-netlink.h"
 
 /* Maximum ARP IP target defined in kernel */
 #define BOND_MAX_ARP_TARGETS    16
@@ -665,11 +667,49 @@ static const NLType rtnl_types[] = {
         [RTM_GETRULE]      = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_routing_policy_rule_type_system, .size = sizeof(struct rtmsg) },
 };
 
-const NLTypeSystem type_system_root = {
+const NLTypeSystem rtnl_type_system_root = {
         .count = ELEMENTSOF(rtnl_types),
         .types = rtnl_types,
 };
 
+
+static const NLType genl_get_family_types[] = {
+        [CTRL_ATTR_FAMILY_NAME] = { .type = NETLINK_TYPE_STRING },
+        [CTRL_ATTR_FAMILY_ID] = { .type = NETLINK_TYPE_U16 },
+};
+
+static const NLTypeSystem genl_get_family_type_system = {
+        .count = ELEMENTSOF(genl_get_family_types),
+        .types = genl_get_family_types,
+};
+
+static const NLType genl_ctrl_id_ctrl_cmds[] = {
+        [CTRL_CMD_GETFAMILY] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_get_family_type_system },
+};
+
+static const NLTypeSystem genl_ctrl_id_ctrl_type_system = {
+        .count = ELEMENTSOF(genl_ctrl_id_ctrl_cmds),
+        .types = genl_ctrl_id_ctrl_cmds,
+};
+
+static const NLType genl_families[] = {
+        [SD_GENL_ID_CTRL]  = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_ctrl_id_ctrl_type_system },
+};
+
+const NLTypeSystem genl_family_type_system_root = {
+        .count = ELEMENTSOF(genl_families),
+        .types = genl_families,
+};
+
+static const NLType genl_types[] = {
+        [GENL_ID_CTRL] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_get_family_type_system, .size = sizeof(struct genlmsghdr) },
+};
+
+const NLTypeSystem genl_type_system_root = {
+        .count = ELEMENTSOF(genl_types),
+        .types = genl_types,
+};
+
 uint16_t type_get_type(const NLType *type) {
         assert(type);
         return type->type;
@@ -703,6 +743,15 @@ uint16_t type_system_get_count(const NLTypeSystem *type_system) {
         return type_system->count;
 }
 
+const NLTypeSystem *type_system_get_root(int protocol) {
+        switch (protocol) {
+                case NETLINK_GENERIC:
+                        return &genl_type_system_root;
+                default: /* NETLINK_ROUTE: */
+                        return &rtnl_type_system_root;
+        }
+}
+
 int type_system_get_type(const NLTypeSystem *type_system, const NLType **ret, uint16_t type) {
         const NLType *nl_type;
 
index 57b46339f9b79880614374822798ff757f5677c1..2012319e8a1971053b9f82e145b8a38e502e318b 100644 (file)
@@ -54,13 +54,16 @@ struct NLTypeSystemUnion {
         const NLTypeSystem *type_systems;
 };
 
-extern const NLTypeSystem type_system_root;
+extern const NLTypeSystem rtnl_type_system_root;
+extern const NLTypeSystem genl_type_system_root;
+extern const NLTypeSystem genl_family_type_system_root;
 
 uint16_t type_get_type(const NLType *type);
 size_t type_get_size(const NLType *type);
 void type_get_type_system(const NLType *type, const NLTypeSystem **ret);
 void type_get_type_system_union(const NLType *type, const NLTypeSystemUnion **ret);
 
+const NLTypeSystem* type_system_get_root(int protocol);
 uint16_t type_system_get_count(const NLTypeSystem *type_system);
 int type_system_get_type(const NLTypeSystem *type_system, const NLType **ret, uint16_t type);
 int type_system_get_type_system(const NLTypeSystem *type_system, const NLTypeSystem **ret, uint16_t type);
index b32fad271a39adab0e363cda686843ecd28ac7ee..7680b30e70c936f115d553c0bc326a41985190fb 100644 (file)
@@ -98,13 +98,13 @@ int rtnl_set_link_properties(sd_netlink **rtnl, int ifindex, const char *alias,
         return 0;
 }
 
-int rtnl_message_new_synthetic_error(int error, uint32_t serial, sd_netlink_message **ret) {
+int rtnl_message_new_synthetic_error(sd_netlink *rtnl, int error, uint32_t serial, sd_netlink_message **ret) {
         struct nlmsgerr *err;
         int r;
 
         assert(error <= 0);
 
-        r = message_new(NULL, ret, NLMSG_ERROR);
+        r = message_new(rtnl, ret, NLMSG_ERROR);
         if (r < 0)
                 return r;
 
index c804f5514cb40527465c7773e57ab2b7b0c65857..795e4dc15c15ff48b3eac9775acd5c9f3274b4cc 100644 (file)
@@ -24,7 +24,7 @@
 
 #include "util.h"
 
-int rtnl_message_new_synthetic_error(int error, uint32_t serial, sd_netlink_message **ret);
+int rtnl_message_new_synthetic_error(sd_netlink *rtnl, int error, uint32_t serial, sd_netlink_message **ret);
 uint32_t rtnl_message_get_serial(sd_netlink_message *m);
 void rtnl_message_seal(sd_netlink_message *m);
 
index 924b0c954fdfdc3c81b2810db157ba45b348e130..d3c4e7130a11d99d2c09faec30bedce3a6def00e 100644 (file)
@@ -46,6 +46,7 @@ static int sd_netlink_new(sd_netlink **ret) {
         rtnl->fd = -1;
         rtnl->sockaddr.nl.nl_family = AF_NETLINK;
         rtnl->original_pid = getpid_cached();
+        rtnl->protocol = -1;
 
         LIST_HEAD_INIT(rtnl->match_callbacks);
 
@@ -106,6 +107,8 @@ static bool rtnl_pid_changed(sd_netlink *rtnl) {
 int sd_netlink_open_fd(sd_netlink **ret, int fd) {
         _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
         int r;
+        int protocol;
+        socklen_t l;
 
         assert_return(ret, -EINVAL);
         assert_return(fd >= 0, -EBADF);
@@ -114,11 +117,18 @@ int sd_netlink_open_fd(sd_netlink **ret, int fd) {
         if (r < 0)
                 return r;
 
+        l = sizeof(protocol);
+        r = getsockopt(fd, SOL_SOCKET, SO_PROTOCOL, &protocol, &l);
+        if (r < 0)
+                return r;
+
         rtnl->fd = fd;
+        rtnl->protocol = protocol;
 
         r = socket_bind(rtnl);
         if (r < 0) {
                 rtnl->fd = -1; /* on failure, the caller remains owner of the fd, hence don't close it here */
+                rtnl->protocol = -1;
                 return r;
         }
 
@@ -128,11 +138,11 @@ int sd_netlink_open_fd(sd_netlink **ret, int fd) {
         return 0;
 }
 
-int sd_netlink_open(sd_netlink **ret) {
+int netlink_open_family(sd_netlink **ret, int family) {
         _cleanup_close_ int fd = -1;
         int r;
 
-        fd = socket_open(NETLINK_ROUTE);
+        fd = socket_open(family);
         if (fd < 0)
                 return fd;
 
@@ -145,6 +155,10 @@ int sd_netlink_open(sd_netlink **ret) {
         return 0;
 }
 
+int sd_netlink_open(sd_netlink **ret) {
+        return netlink_open_family(ret, NETLINK_ROUTE);
+}
+
 int sd_netlink_inc_rcvbuf(sd_netlink *rtnl, size_t size) {
         assert_return(rtnl, -EINVAL);
         assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
@@ -309,7 +323,7 @@ static int process_timeout(sd_netlink *rtnl) {
         if (c->timeout > n)
                 return 0;
 
-        r = rtnl_message_new_synthetic_error(-ETIMEDOUT, c->serial, &m);
+        r = rtnl_message_new_synthetic_error(rtnl, -ETIMEDOUT, c->serial, &m);
         if (r < 0)
                 return r;
 
index 73e5af0060014675b1b5df0b6f6c9ef89e422dc7..9ccc8ea607b00902bebacc6f5da8b2842992e990 100644 (file)
@@ -143,13 +143,13 @@ static void test_address_get(sd_netlink *rtnl, int ifindex) {
 
 }
 
-static void test_route(void) {
+static void test_route(sd_netlink *rtnl) {
         _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req;
         struct in_addr addr, addr_data;
         uint32_t index = 2, u32_data;
         int r;
 
-        r = sd_rtnl_message_new_route(NULL, &req, RTM_NEWROUTE, AF_INET, RTPROT_STATIC);
+        r = sd_rtnl_message_new_route(rtnl, &req, RTM_NEWROUTE, AF_INET, RTPROT_STATIC);
         if (r < 0) {
                 log_error_errno(r, "Could not create RTM_NEWROUTE message: %m");
                 return;
@@ -291,13 +291,13 @@ static void test_pipe(int ifindex) {
         assert_se((rtnl = sd_netlink_unref(rtnl)) == NULL);
 }
 
-static void test_container(void) {
+static void test_container(sd_netlink *rtnl) {
         _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
         uint16_t u16_data;
         uint32_t u32_data;
         const char *string_data;
 
-        assert_se(sd_rtnl_message_new_link(NULL, &m, RTM_NEWLINK, 0) >= 0);
+        assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_NEWLINK, 0) >= 0);
 
         assert_se(sd_netlink_message_open_container(m, IFLA_LINKINFO) >= 0);
         assert_se(sd_netlink_message_open_container_union(m, IFLA_INFO_DATA, "vlan") >= 0);
@@ -369,10 +369,10 @@ static void test_get_addresses(sd_netlink *rtnl) {
         }
 }
 
-static void test_message(void) {
+static void test_message(sd_netlink *rtnl) {
         _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
 
-        assert_se(rtnl_message_new_synthetic_error(-ETIMEDOUT, 1, &m) >= 0);
+        assert_se(rtnl_message_new_synthetic_error(rtnl, -ETIMEDOUT, 1, &m) >= 0);
         assert_se(sd_netlink_message_get_errno(m) == -ETIMEDOUT);
 }
 
@@ -384,19 +384,19 @@ int main(void) {
         int if_loopback;
         uint16_t type;
 
-        test_message();
-
         test_match();
 
         test_multiple();
 
-        test_route();
-
-        test_container();
-
         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);
 
index 7cf110672f261b52ca9b4096616d39284fc58d7c..4adaac26b8f3bba7a8cfc867ab8dd4103df19cf3 100644 (file)
@@ -114,7 +114,7 @@ static void netdev_cancel_callbacks(NetDev *netdev) {
         if (!netdev)
                 return;
 
-        rtnl_message_new_synthetic_error(-ENODEV, 0, &m);
+        rtnl_message_new_synthetic_error(netdev->manager->rtnl, -ENODEV, 0, &m);
 
         while ((callback = netdev->callbacks)) {
                 if (m) {
@@ -322,7 +322,7 @@ int netdev_enslave(NetDev *netdev, Link *link, sd_netlink_message_handler_t call
         } else if (IN_SET(netdev->state, NETDEV_STATE_LINGER, NETDEV_STATE_FAILED)) {
                 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
 
-                r = rtnl_message_new_synthetic_error(-ENODEV, 0, &m);
+                r = rtnl_message_new_synthetic_error(netdev->manager->rtnl, -ENODEV, 0, &m);
                 if (r >= 0)
                         callback(netdev->manager->rtnl, m, link);
         } else {
index e3c514c8044829c03fedc3713a2d6c5c412a1026..9cd2b9d3db5f5eab9ed073617bebb49b03b1e00f 100644 (file)
@@ -912,6 +912,26 @@ static int systemd_netlink_fd(void) {
         return rtnl_fd;
 }
 
+static int manager_connect_genl(Manager *m) {
+        int r;
+
+        assert(m);
+
+        r = sd_genl_socket_open(&m->genl);
+        if (r < 0)
+                return r;
+
+        r = sd_netlink_inc_rcvbuf(m->genl, RCVBUF_SIZE);
+        if (r < 0)
+                return r;
+
+        r = sd_netlink_attach_event(m->genl, m->event, 0);
+        if (r < 0)
+                return r;
+
+        return 0;
+}
+
 static int manager_connect_rtnl(Manager *m) {
         int fd, r;
 
@@ -1256,6 +1276,10 @@ int manager_new(Manager **ret, sd_event *event) {
         if (r < 0)
                 return r;
 
+        r = manager_connect_genl(m);
+        if (r < 0)
+                return r;
+
         r = manager_connect_udev(m);
         if (r < 0)
                 return r;
@@ -1266,6 +1290,14 @@ int manager_new(Manager **ret, sd_event *event) {
 
         LIST_HEAD_INIT(m->networks);
 
+        r = sd_resolve_default(&m->resolve);
+        if (r < 0)
+                return r;
+
+        r = sd_resolve_attach_event(m->resolve, m->event, 0);
+        if (r < 0)
+                return r;
+
         r = setup_default_address_pool(m);
         if (r < 0)
                 return r;
@@ -1315,6 +1347,8 @@ void manager_free(Manager *m) {
         sd_netlink_unref(m->rtnl);
         sd_event_unref(m->event);
 
+        sd_resolve_unref(m->resolve);
+
         sd_event_source_unref(m->udev_event_source);
         udev_monitor_unref(m->udev_monitor);
         udev_unref(m->udev);
index 186cb418911b3ed033bd766f22d215183f9236a2..3cd9f30d14553b94a3372d88e5f331a2edeff46d 100644 (file)
@@ -25,6 +25,7 @@
 #include "sd-bus.h"
 #include "sd-event.h"
 #include "sd-netlink.h"
+#include "sd-resolve.h"
 #include "udev.h"
 
 #include "dhcp-identifier.h"
@@ -39,7 +40,10 @@ extern const char* const network_dirs[];
 
 struct Manager {
         sd_netlink *rtnl;
+        /* lazy initialized */
+        sd_netlink *genl;
         sd_event *event;
+        sd_resolve *resolve;
         sd_event_source *bus_retry_event_source;
         sd_bus *bus;
         sd_bus_slot *prepare_for_sleep_slot;
index d6e3816c64cd441dac2462a4d0b842ed17c287e0..7c4d51ea798457080300fd381c35f238fd22b317 100644 (file)
@@ -34,7 +34,9 @@
 _SD_BEGIN_DECLARATIONS;
 
 typedef struct sd_netlink sd_netlink;
+typedef struct sd_genl_socket sd_genl_socket;
 typedef struct sd_netlink_message sd_netlink_message;
+typedef enum {SD_GENL_ID_CTRL} sd_genl_family;
 
 /* callback */
 
@@ -94,6 +96,9 @@ int sd_netlink_message_read_in6_addr(sd_netlink_message *m, unsigned short type,
 int sd_netlink_message_enter_container(sd_netlink_message *m, unsigned short type);
 int sd_netlink_message_exit_container(sd_netlink_message *m);
 
+int sd_netlink_message_open_array(sd_netlink_message *m, uint16_t type);
+int sd_netlink_message_cancel_array(sd_netlink_message *m);
+
 int sd_netlink_message_rewind(sd_netlink_message *m);
 
 sd_netlink_message *sd_netlink_message_next(sd_netlink_message *m);
@@ -177,6 +182,10 @@ int sd_rtnl_message_routing_policy_rule_get_rtm_type(sd_netlink_message *m, unsi
 _SD_DEFINE_POINTER_CLEANUP_FUNC(sd_netlink, sd_netlink_unref);
 _SD_DEFINE_POINTER_CLEANUP_FUNC(sd_netlink_message, sd_netlink_message_unref);
 
+/* genl */
+int sd_genl_socket_open(sd_netlink **nl);
+int sd_genl_message_new(sd_netlink *nl, sd_genl_family family, uint8_t cmd, sd_netlink_message **m);
+
 _SD_END_DECLARATIONS;
 
 #endif