]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
sd-netlink: drop sd_genl_family_t and introduce GenericNetlinkFamily
authorYu Watanabe <watanabe.yu+github@gmail.com>
Tue, 24 Aug 2021 09:11:20 +0000 (18:11 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Sun, 29 Aug 2021 09:10:43 +0000 (18:10 +0900)
Kernel manages each genl family by its name, e.g. "nlctrl" or WG_GENL_NAME,
and its ID (used for nlmsg_type) is determined dynamically when the
corresponding module is loaded.

This commit makes sd-netlink follow the same way; now, sd_genl_family_t
is dropped, and sd_genl_message_new() takes a genl family name. Each
genl family is resolved when it is used first time, and its information
is stored in GenericNetlinkFamily.

18 files changed:
src/libsystemd/sd-netlink/netlink-genl.c
src/libsystemd/sd-netlink/netlink-genl.h
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-genl.c
src/libsystemd/sd-netlink/netlink-types.c
src/libsystemd/sd-netlink/netlink-types.h
src/libsystemd/sd-netlink/sd-netlink.c
src/libsystemd/sd-netlink/test-netlink.c
src/network/netdev/batadv.c
src/network/netdev/fou-tunnel.c
src/network/netdev/l2tp-tunnel.c
src/network/netdev/macsec.c
src/network/netdev/wireguard.c
src/network/test-network-tables.c
src/shared/wifi-util.c
src/systemd/sd-netlink.h

index 06406add496edcfcf4c948515bc7bee6aae36596..1aeca0c5cff997d557d3d5aed41debf3d046722f 100644 (file)
 #include "alloc-util.h"
 #include "netlink-genl.h"
 #include "netlink-internal.h"
+#include "netlink-types.h"
 
-typedef struct {
-        const char* name;
-        uint8_t version;
-} genl_family;
-
-static const genl_family genl_families[] = {
-        [SD_GENL_ID_CTRL]   = { .name = "",          .version = 1 },
-        [SD_GENL_WIREGUARD] = { .name = "wireguard", .version = 1 },
-        [SD_GENL_FOU]       = { .name = "fou",       .version = 1 },
-        [SD_GENL_L2TP]      = { .name = "l2tp",      .version = 1 },
-        [SD_GENL_MACSEC]    = { .name = "macsec",    .version = 1 },
-        [SD_GENL_NL80211]   = { .name = "nl80211",   .version = 1 },
-        [SD_GENL_BATADV]    = { .name = "batadv",    .version = 1 },
+typedef struct GenericNetlinkFamily {
+        sd_netlink *genl;
+
+        const NLTypeSystem *type_system;
+
+        uint16_t id; /* a.k.a nlmsg_type */
+        char *name;
+} GenericNetlinkFamily;
+
+static const GenericNetlinkFamily nlctrl_static = {
+        .id = GENL_ID_CTRL,
+        .name = (char*) CTRL_GENL_NAME,
 };
 
-int sd_genl_socket_open(sd_netlink **ret) {
-        return netlink_open_family(ret, NETLINK_GENERIC);
+static GenericNetlinkFamily *genl_family_free(GenericNetlinkFamily *f) {
+        if (!f)
+                return NULL;
+
+        if (f->genl) {
+                if (f->id > 0)
+                        hashmap_remove(f->genl->genl_family_by_id, UINT_TO_PTR(f->id));
+                if (f->name)
+                        hashmap_remove(f->genl->genl_family_by_name, f->name);
+        }
+
+        free(f->name);
+
+        return mfree(f);
 }
 
-static int genl_message_new(sd_netlink *nl, sd_genl_family_t family, uint16_t nlmsg_type, uint8_t cmd, sd_netlink_message **ret) {
-        _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
-        const NLType *type;
-        size_t size;
+DEFINE_TRIVIAL_CLEANUP_FUNC(GenericNetlinkFamily*, genl_family_free);
+
+void genl_clear_family(sd_netlink *nl) {
+        assert(nl);
+
+        nl->genl_family_by_name = hashmap_free_with_destructor(nl->genl_family_by_name, genl_family_free);
+        nl->genl_family_by_id = hashmap_free_with_destructor(nl->genl_family_by_id, genl_family_free);
+}
+
+static int genl_family_new(
+                sd_netlink *nl,
+                const char *expected_family_name,
+                const NLTypeSystem *type_system,
+                sd_netlink_message *message,
+                const GenericNetlinkFamily **ret) {
+
+        _cleanup_(genl_family_freep) GenericNetlinkFamily *f = NULL;
+        const char *family_name;
         int r;
 
         assert(nl);
-        assert(nl->protocol == NETLINK_GENERIC);
+        assert(expected_family_name);
+        assert(type_system);
+        assert(message);
         assert(ret);
 
-        r = type_system_root_get_type(nl, &type, nlmsg_type);
+        f = new(GenericNetlinkFamily, 1);
+        if (!f)
+                return -ENOMEM;
+
+        *f = (GenericNetlinkFamily) {
+                .type_system = type_system,
+        };
+
+        if (sd_netlink_message_is_error(message)) {
+                int e;
+
+                /* Kernel does not support the genl family? To prevent from resolving the family name
+                 * again, let's store the family with zero id to indicate that. */
+
+                e = sd_netlink_message_get_errno(message);
+                if (e >= 0) /* Huh? */
+                        e = -EOPNOTSUPP;
+
+                f->name = strdup(expected_family_name);
+                if (!f->name)
+                        return e;
+
+                if (hashmap_ensure_put(&nl->genl_family_by_name, &string_hash_ops, f->name, f) < 0)
+                        return e;
+
+                f->genl = nl;
+                TAKE_PTR(f);
+                return e;
+        }
+
+        r = sd_genl_message_get_family_name(nl, message, &family_name);
         if (r < 0)
                 return r;
 
-        r = message_new_empty(nl, &m);
+        if (!streq(family_name, CTRL_GENL_NAME))
+                return -EINVAL;
+
+        r = sd_netlink_message_read_u16(message, CTRL_ATTR_FAMILY_ID, &f->id);
         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;
-        m->hdr->nlmsg_len = size;
-        m->hdr->nlmsg_type = nlmsg_type;
+        r = sd_netlink_message_read_string_strdup(message, CTRL_ATTR_FAMILY_NAME, &f->name);
+        if (r < 0)
+                return r;
 
-        m->containers[0].type_system = type_get_type_system(type);
+        if (!streq(f->name, expected_family_name))
+                return -EINVAL;
 
-        *(struct genlmsghdr *) NLMSG_DATA(m->hdr) = (struct genlmsghdr) {
-                .cmd = cmd,
-                .version = genl_families[family].version,
-        };
+        r = hashmap_ensure_put(&nl->genl_family_by_id, NULL, UINT_TO_PTR(f->id), f);
+        if (r < 0)
+                return r;
 
-        *ret = TAKE_PTR(m);
+        r = hashmap_ensure_put(&nl->genl_family_by_name, &string_hash_ops, f->name, f);
+        if (r < 0) {
+                hashmap_remove(nl->genl_family_by_id, UINT_TO_PTR(f->id));
+                return r;
+        }
 
+        f->genl = nl;
+        *ret = TAKE_PTR(f);
         return 0;
 }
 
-static int lookup_nlmsg_type(sd_netlink *nl, sd_genl_family_t family, uint16_t *ret) {
-        _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
-        uint16_t u;
-        void *v;
-        int r;
-
-        assert(nl);
-        assert(nl->protocol == NETLINK_GENERIC);
+static int genl_family_get_type_system(const GenericNetlinkFamily *family, const NLTypeSystem **ret) {
+        assert(family);
         assert(ret);
 
-        if (family == SD_GENL_ID_CTRL) {
-                *ret = GENL_ID_CTRL;
+        if (family->type_system) {
+                *ret = family->type_system;
                 return 0;
         }
 
-        v = hashmap_get(nl->genl_family_to_nlmsg_type, INT_TO_PTR(family));
-        if (v) {
-                *ret = PTR_TO_UINT(v);
-                return 0;
-        }
+        return genl_get_type_system_by_name(family->name, ret);
+}
+
+static int genl_message_new(
+                sd_netlink *nl,
+                const GenericNetlinkFamily *family,
+                uint8_t cmd,
+                sd_netlink_message **ret) {
+
+        _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
+        const NLTypeSystem *type_system;
+        int r;
 
-        r = genl_message_new(nl, SD_GENL_ID_CTRL, GENL_ID_CTRL, CTRL_CMD_GETFAMILY, &req);
+        assert(nl);
+        assert(nl->protocol == NETLINK_GENERIC);
+        assert(family);
+        assert(ret);
+
+        r = genl_family_get_type_system(family, &type_system);
         if (r < 0)
                 return r;
 
-        r = sd_netlink_message_append_string(req, CTRL_ATTR_FAMILY_NAME, genl_families[family].name);
+        r = message_new_full(nl, family->id, type_system, sizeof(struct genlmsghdr), &m);
         if (r < 0)
                 return r;
 
-        r = sd_netlink_call(nl, req, 0, &reply);
+        *(struct genlmsghdr *) NLMSG_DATA(m->hdr) = (struct genlmsghdr) {
+                .cmd = cmd,
+                .version = 1,
+        };
+
+        *ret = TAKE_PTR(m);
+        return 0;
+}
+
+static int genl_family_get_by_name_internal(
+                sd_netlink *nl,
+                const GenericNetlinkFamily *ctrl,
+                const char *name,
+                const GenericNetlinkFamily **ret) {
+
+        _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
+        const NLTypeSystem *type_system;
+        int r;
+
+        assert(nl);
+        assert(nl->protocol == NETLINK_GENERIC);
+        assert(ctrl);
+        assert(name);
+        assert(ret);
+
+        r = genl_get_type_system_by_name(name, &type_system);
         if (r < 0)
                 return r;
 
-        r = sd_netlink_message_read_u16(reply, CTRL_ATTR_FAMILY_ID, &u);
+        r = genl_message_new(nl, ctrl, CTRL_CMD_GETFAMILY, &req);
         if (r < 0)
                 return r;
 
-        r = hashmap_ensure_put(&nl->genl_family_to_nlmsg_type, NULL, INT_TO_PTR(family), UINT_TO_PTR(u));
+        r = sd_netlink_message_append_string(req, CTRL_ATTR_FAMILY_NAME, name);
         if (r < 0)
                 return r;
 
-        r = hashmap_ensure_put(&nl->nlmsg_type_to_genl_family, NULL, UINT_TO_PTR(u), INT_TO_PTR(family));
+        r = sd_netlink_call(nl, req, 0, &reply);
         if (r < 0)
                 return r;
 
-        *ret = u;
-        return 0;
+        return genl_family_new(nl, name, type_system, reply, ret);
 }
 
-int sd_genl_message_new(sd_netlink *nl, sd_genl_family_t family, uint8_t cmd, sd_netlink_message **ret) {
-        uint16_t nlmsg_type = 0;  /* Unnecessary initialization to appease gcc */
+static int genl_family_get_by_name(sd_netlink *nl, const char *name, const GenericNetlinkFamily **ret) {
+        const GenericNetlinkFamily *f, *ctrl;
         int r;
 
-        assert_return(nl, -EINVAL);
-        assert_return(nl->protocol == NETLINK_GENERIC, -EINVAL);
-        assert_return(ret, -EINVAL);
+        assert(nl);
+        assert(nl->protocol == NETLINK_GENERIC);
+        assert(name);
+        assert(ret);
 
-        r = lookup_nlmsg_type(nl, family, &nlmsg_type);
-        if (r < 0)
-                return r;
+        f = hashmap_get(nl->genl_family_by_name, name);
+        if (f) {
+                if (f->id == 0) /* kernel does not support the family. */
+                        return -EOPNOTSUPP;
+
+                *ret = f;
+                return 0;
+        }
+
+        if (streq(name, CTRL_GENL_NAME))
+                return genl_family_get_by_name_internal(nl, &nlctrl_static, CTRL_GENL_NAME, ret);
+
+        ctrl = hashmap_get(nl->genl_family_by_name, CTRL_GENL_NAME);
+        if (!ctrl) {
+                r = genl_family_get_by_name_internal(nl, &nlctrl_static, CTRL_GENL_NAME, &ctrl);
+                if (r < 0)
+                        return r;
+        }
 
-        return genl_message_new(nl, family, nlmsg_type, cmd, ret);
+        return genl_family_get_by_name_internal(nl, ctrl, name, ret);
 }
 
-int nlmsg_type_to_genl_family(const sd_netlink *nl, uint16_t nlmsg_type, sd_genl_family_t *ret) {
-        void *p;
+static int genl_family_get_by_id(sd_netlink *nl, uint16_t id, const GenericNetlinkFamily **ret) {
+        const GenericNetlinkFamily *f;
 
         assert(nl);
         assert(nl->protocol == NETLINK_GENERIC);
         assert(ret);
 
-        if (nlmsg_type == NLMSG_ERROR)
-                *ret = SD_GENL_ERROR;
-        else if (nlmsg_type == NLMSG_DONE)
-                *ret = SD_GENL_DONE;
-        else if (nlmsg_type == GENL_ID_CTRL)
-                *ret = SD_GENL_ID_CTRL;
-        else {
-                p = hashmap_get(nl->nlmsg_type_to_genl_family, UINT_TO_PTR(nlmsg_type));
-                if (!p)
-                        return -EOPNOTSUPP;
+        f = hashmap_get(nl->genl_family_by_id, UINT_TO_PTR(id));
+        if (f) {
+                *ret = f;
+                return 0;
+        }
 
-                *ret = PTR_TO_INT(p);
+        if (id == GENL_ID_CTRL) {
+                *ret = &nlctrl_static;
+                return 0;
         }
 
+        return -ENOENT;
+}
+
+int genl_get_type_system_and_header_size(
+                sd_netlink *nl,
+                uint16_t id,
+                const NLTypeSystem **ret_type_system,
+                size_t *ret_header_size) {
+
+        const GenericNetlinkFamily *f;
+        int r;
+
+        assert(nl);
+        assert(nl->protocol == NETLINK_GENERIC);
+
+        r = genl_family_get_by_id(nl, id, &f);
+        if (r < 0)
+                return r;
+
+        if (ret_type_system) {
+                r = genl_family_get_type_system(f, ret_type_system);
+                if (r < 0)
+                        return r;
+        }
+        if (ret_header_size)
+                *ret_header_size = sizeof(struct genlmsghdr);
         return 0;
 }
 
-int sd_genl_message_get_family(sd_netlink *nl, sd_netlink_message *m, sd_genl_family_t *ret) {
+int sd_genl_message_new(sd_netlink *nl, const char *family_name, uint8_t cmd, sd_netlink_message **ret) {
+        const GenericNetlinkFamily *family;
+        int r;
+
+        assert_return(nl, -EINVAL);
+        assert_return(nl->protocol == NETLINK_GENERIC, -EINVAL);
+        assert_return(family_name, -EINVAL);
+        assert_return(ret, -EINVAL);
+
+        r = genl_family_get_by_name(nl, family_name, &family);
+        if (r < 0)
+                return r;
+
+        return genl_message_new(nl, family, cmd, ret);
+}
+
+int sd_genl_message_get_family_name(sd_netlink *nl, sd_netlink_message *m, const char **ret) {
+        const GenericNetlinkFamily *family;
         uint16_t nlmsg_type;
         int r;
 
@@ -167,5 +315,14 @@ int sd_genl_message_get_family(sd_netlink *nl, sd_netlink_message *m, sd_genl_fa
         if (r < 0)
                 return r;
 
-        return nlmsg_type_to_genl_family(nl, nlmsg_type, ret);
+        r = genl_family_get_by_id(nl, nlmsg_type, &family);
+        if (r < 0)
+                return r;
+
+        *ret = family->name;
+        return 0;
+}
+
+int sd_genl_socket_open(sd_netlink **ret) {
+        return netlink_open_family(ret, NETLINK_GENERIC);
 }
index fd0461426b841408d86d08927b5822cd23c25a24..b06be05952d7856576ec336b97f61428a3d5c15b 100644 (file)
@@ -3,4 +3,6 @@
 
 #include "sd-netlink.h"
 
-int nlmsg_type_to_genl_family(const sd_netlink *nl, uint16_t type, sd_genl_family_t *ret);
+#define CTRL_GENL_NAME "nlctrl"
+
+void genl_clear_family(sd_netlink *nl);
index e19b460bcd9ca199a9596e68488e67264e669fb4..2594885fe65030c0285d1a187ba3e943148fa3d7 100644 (file)
@@ -95,8 +95,8 @@ struct sd_netlink {
         sd_event_source *exit_event_source;
         sd_event *event;
 
-        Hashmap *genl_family_to_nlmsg_type;
-        Hashmap *nlmsg_type_to_genl_family;
+        Hashmap *genl_family_by_name;
+        Hashmap *genl_family_by_id;
 };
 
 struct netlink_attribute {
index 325c570b2edbed42fe85ad61d97043d7de74f942..0c9b5454b630e787a48f841d27a3fb4e7f589071 100644 (file)
@@ -80,20 +80,18 @@ int message_new_full(
 }
 
 int message_new(sd_netlink *nl, sd_netlink_message **ret, uint16_t type) {
-        const NLType *nl_type;
+        const NLTypeSystem *type_system;
+        size_t size;
         int r;
 
         assert_return(nl, -EINVAL);
         assert_return(ret, -EINVAL);
 
-        r = type_system_root_get_type(nl, &nl_type, type);
+        r = type_system_root_get_type_system_and_header_size(nl, type, &type_system, &size);
         if (r < 0)
                 return r;
 
-        if (type_get_type(nl_type) != NETLINK_TYPE_NESTED)
-                return -EINVAL;
-
-        return message_new_full(nl, type, type_get_type_system(nl_type), type_get_size(nl_type), ret);
+        return message_new_full(nl, type, type_system, size, ret);
 }
 
 int message_new_synthetic_error(sd_netlink *nl, int error, uint32_t serial, sd_netlink_message **ret) {
@@ -1319,8 +1317,6 @@ static int netlink_message_parse_error(sd_netlink_message *m) {
 }
 
 int sd_netlink_message_rewind(sd_netlink_message *m, sd_netlink *nl) {
-        const NLType *nl_type;
-        uint16_t type;
         size_t size;
         int r;
 
@@ -1341,28 +1337,18 @@ int sd_netlink_message_rewind(sd_netlink_message *m, sd_netlink *nl) {
 
         assert(m->hdr);
 
-        r = type_system_root_get_type(nl, &nl_type, m->hdr->nlmsg_type);
+        r = type_system_root_get_type_system_and_header_size(nl, m->hdr->nlmsg_type,
+                                                             &m->containers[0].type_system, &size);
         if (r < 0)
                 return r;
 
-        type = type_get_type(nl_type);
-        size = type_get_size(nl_type);
-
-        if (type == NETLINK_TYPE_NESTED) {
-                m->containers[0].type_system = type_get_type_system(nl_type);
+        if (sd_netlink_message_is_error(m))
+                return netlink_message_parse_error(m);
 
-                if (sd_netlink_message_is_error(m))
-                        r = netlink_message_parse_error(m);
-                else
-                        r = netlink_container_parse(m,
-                                                    &m->containers[m->n_containers],
-                                                    (struct rtattr*)((uint8_t*) NLMSG_DATA(m->hdr) + NLMSG_ALIGN(size)),
-                                                    NLMSG_PAYLOAD(m->hdr, size));
-                if (r < 0)
-                        return r;
-        }
-
-        return 0;
+        return netlink_container_parse(m,
+                                       &m->containers[0],
+                                       (struct rtattr*)((uint8_t*) NLMSG_DATA(m->hdr) + NLMSG_ALIGN(size)),
+                                       NLMSG_PAYLOAD(m->hdr, size));
 }
 
 void message_seal(sd_netlink_message *m) {
index 1168f4edc00295dc89561074e6d73801eec44737..15c2789beee457eeec2cd255c2117de701be279c 100644 (file)
@@ -326,7 +326,7 @@ int socket_read_message(sd_netlink *nl) {
 
         for (struct nlmsghdr *new_msg = nl->rbuffer; NLMSG_OK(new_msg, len) && !done; new_msg = NLMSG_NEXT(new_msg, len)) {
                 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
-                const NLType *nl_type;
+                size_t size;
 
                 if (!group && new_msg->nlmsg_pid != nl->sockaddr.nl.nl_pid)
                         /* not broadcast and not for us */
@@ -346,7 +346,7 @@ int socket_read_message(sd_netlink *nl) {
                 }
 
                 /* check that we support this message type */
-                r = type_system_root_get_type(nl, &nl_type, new_msg->nlmsg_type);
+                r = type_system_root_get_type_system_and_header_size(nl, new_msg->nlmsg_type, NULL, &size);
                 if (r < 0) {
                         if (r == -EOPNOTSUPP)
                                 log_debug("sd-netlink: ignored message with unknown type: %i",
@@ -356,7 +356,7 @@ int socket_read_message(sd_netlink *nl) {
                 }
 
                 /* check that the size matches the message type */
-                if (new_msg->nlmsg_len < NLMSG_LENGTH(type_get_size(nl_type))) {
+                if (new_msg->nlmsg_len < NLMSG_LENGTH(size)) {
                         log_debug("sd-netlink: message is shorter than expected, dropping");
                         continue;
                 }
index 33e80a1745082db9495a1dd4319093bbb9e84660..dde682f6262e5e956fc4e1f807bb6922c0c29658 100644 (file)
@@ -44,8 +44,6 @@ static const NLType genl_ctrl_types[] = {
         [CTRL_ATTR_OP]           = { .type = NETLINK_TYPE_U32 },
 };
 
-DEFINE_TYPE_SYSTEM(genl_ctrl);
-
 /***************** genl batadv type systems *****************/
 static const NLType genl_batadv_types[] = {
         [BATADV_ATTR_VERSION]                       = { .type = NETLINK_TYPE_STRING },
@@ -110,8 +108,6 @@ static const NLType genl_batadv_types[] = {
         [BATADV_ATTR_THROUGHPUT_OVERRIDE]           = { .type = NETLINK_TYPE_U32 },
 };
 
-DEFINE_TYPE_SYSTEM(genl_batadv);
-
 /***************** genl fou type systems *****************/
 static const NLType genl_fou_types[] = {
         [FOU_ATTR_PORT]              = { .type = NETLINK_TYPE_U16 },
@@ -127,8 +123,6 @@ static const NLType genl_fou_types[] = {
         [FOU_ATTR_IFINDEX]           = { .type = NETLINK_TYPE_U32},
 };
 
-DEFINE_TYPE_SYSTEM(genl_fou);
-
 /***************** genl l2tp type systems *****************/
 static const NLType genl_l2tp_types[] = {
         [L2TP_ATTR_PW_TYPE]           = { .type = NETLINK_TYPE_U16 },
@@ -160,8 +154,6 @@ static const NLType genl_l2tp_types[] = {
         [L2TP_ATTR_UDP_ZERO_CSUM6_RX] = { .type = NETLINK_TYPE_FLAG },
 };
 
-DEFINE_TYPE_SYSTEM(genl_l2tp);
-
 /***************** genl macsec type systems *****************/
 static const NLType genl_macsec_rxsc_types[] = {
         [MACSEC_RXSC_ATTR_SCI] = { .type = NETLINK_TYPE_U64 },
@@ -185,8 +177,6 @@ static const NLType genl_macsec_types[] = {
         [MACSEC_ATTR_SA_CONFIG]   = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_macsec_sa_type_system },
 };
 
-DEFINE_TYPE_SYSTEM(genl_macsec);
-
 /***************** genl nl80211 type systems *****************/
 static const NLType genl_nl80211_types[] = {
         [NL80211_ATTR_IFINDEX] = { .type = NETLINK_TYPE_U32 },
@@ -195,8 +185,6 @@ static const NLType genl_nl80211_types[] = {
         [NL80211_ATTR_IFTYPE]  = { .type = NETLINK_TYPE_U32 },
 };
 
-DEFINE_TYPE_SYSTEM(genl_nl80211);
-
 /***************** genl wireguard type systems *****************/
 static const NLType genl_wireguard_allowedip_types[] = {
         [WGALLOWEDIP_A_FAMILY]    = { .type = NETLINK_TYPE_U16 },
@@ -227,28 +215,20 @@ static const NLType genl_wireguard_types[] = {
         [WGDEVICE_A_PEERS]       = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_wireguard_peer_type_system },
 };
 
-DEFINE_TYPE_SYSTEM(genl_wireguard);
-
 /***************** genl families *****************/
-static const NLType genl_types[] = {
-        [SD_GENL_ID_CTRL]   = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_ctrl_type_system,      .size = sizeof(struct genlmsghdr) },
-        [SD_GENL_WIREGUARD] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_wireguard_type_system, .size = sizeof(struct genlmsghdr) },
-        [SD_GENL_FOU]       = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_fou_type_system,       .size = sizeof(struct genlmsghdr) },
-        [SD_GENL_L2TP]      = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_l2tp_type_system,      .size = sizeof(struct genlmsghdr) },
-        [SD_GENL_MACSEC]    = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_macsec_type_system,    .size = sizeof(struct genlmsghdr) },
-        [SD_GENL_NL80211]   = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_nl80211_type_system,   .size = sizeof(struct genlmsghdr) },
-        [SD_GENL_BATADV]    = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_batadv_type_system,    .size = sizeof(struct genlmsghdr) },
+static const NLTypeSystemUnionElement genl_type_systems[] = {
+        { .name = CTRL_GENL_NAME,    .type_system = TYPE_SYSTEM_FROM_TYPE(genl_ctrl),      },
+        { .name = BATADV_NL_NAME,    .type_system = TYPE_SYSTEM_FROM_TYPE(genl_batadv),    },
+        { .name = FOU_GENL_NAME,     .type_system = TYPE_SYSTEM_FROM_TYPE(genl_fou),       },
+        { .name = L2TP_GENL_NAME,    .type_system = TYPE_SYSTEM_FROM_TYPE(genl_l2tp),      },
+        { .name = MACSEC_GENL_NAME,  .type_system = TYPE_SYSTEM_FROM_TYPE(genl_macsec),    },
+        { .name = NL80211_GENL_NAME, .type_system = TYPE_SYSTEM_FROM_TYPE(genl_nl80211),   },
+        { .name = WG_GENL_NAME,      .type_system = TYPE_SYSTEM_FROM_TYPE(genl_wireguard), },
 };
 
-DEFINE_TYPE_SYSTEM(genl);
-
-int genl_get_type(sd_netlink *genl, uint16_t nlmsg_type, const NLType **ret) {
-        sd_genl_family_t family;
-        int r;
-
-        r = nlmsg_type_to_genl_family(genl, nlmsg_type, &family);
-        if (r < 0)
-                return r;
+/* This is the root type system union, so match_attribute is not necessary. */
+DEFINE_TYPE_SYSTEM_UNION_MATCH_SIBLING(genl, 0);
 
-        return type_system_get_type(&genl_type_system, ret, family);
+int genl_get_type_system_by_name(const char *name, const NLTypeSystem **ret) {
+        return type_system_union_get_type_system_by_string(&genl_type_system_union, ret, name);
 }
index 0f17e7e8adcd117df227394791d34323a3d62ca2..7d6caf004b272c7a7e9b5bd93e8c89fb133c2b52 100644 (file)
@@ -2,6 +2,7 @@
 
 #include <linux/netlink.h>
 
+#include "netlink-genl.h"
 #include "netlink-internal.h"
 #include "netlink-types-internal.h"
 
@@ -54,20 +55,43 @@ uint16_t type_system_get_count(const NLTypeSystem *type_system) {
         return type_system->count;
 }
 
-int type_system_root_get_type(sd_netlink *nl, const NLType **ret, uint16_t type) {
-        if (!nl || IN_SET(type, NLMSG_DONE, NLMSG_ERROR))
-                return type_system_get_type(&basic_type_system, ret, type);
-
-        switch(nl->protocol) {
-        case NETLINK_ROUTE:
-                return rtnl_get_type(type, ret);
-        case NETLINK_NETFILTER:
-                return nfnl_get_type(type, ret);
-        case NETLINK_GENERIC:
-                return genl_get_type(nl, type, ret);
-        default:
+int type_system_root_get_type_system_and_header_size(
+                sd_netlink *nl,
+                uint16_t type,
+                const NLTypeSystem **ret_type_system,
+                size_t *ret_header_size) {
+
+        const NLType *nl_type;
+        int r;
+
+        assert(nl);
+
+        if (IN_SET(type, NLMSG_DONE, NLMSG_ERROR))
+                r = type_system_get_type(&basic_type_system, &nl_type, type);
+        else
+                switch(nl->protocol) {
+                case NETLINK_ROUTE:
+                        r = rtnl_get_type(type, &nl_type);
+                        break;
+                case NETLINK_NETFILTER:
+                        r = nfnl_get_type(type, &nl_type);
+                        break;
+                case NETLINK_GENERIC:
+                        return genl_get_type_system_and_header_size(nl, type, ret_type_system, ret_header_size);
+                default:
+                        return -EOPNOTSUPP;
+                }
+        if (r < 0)
+                return r;
+
+        if (type_get_type(nl_type) != NETLINK_TYPE_NESTED)
                 return -EOPNOTSUPP;
-        }
+
+        if (ret_type_system)
+                *ret_type_system = type_get_type_system(nl_type);
+        if (ret_header_size)
+                *ret_header_size = type_get_size(nl_type);
+        return 0;
 }
 
 int type_system_get_type(const NLTypeSystem *type_system, const NLType **ret, uint16_t type) {
index baab1dbdb01a459bcf3da3fc2aadb360ad4ee375..f8261b681ce3752f5e14c2e73090e573e74fe0ca 100644 (file)
@@ -37,15 +37,25 @@ typedef struct NLType NLType;
 
 int rtnl_get_type(uint16_t nlmsg_type, const NLType **ret);
 int nfnl_get_type(uint16_t nlmsg_type, const NLType **ret);
-int genl_get_type(sd_netlink *genl, uint16_t nlmsg_type, const NLType **ret);
+int genl_get_type_system_by_name(const char *name, const NLTypeSystem **ret);
+int genl_get_type_system_and_header_size(
+                sd_netlink *nl,
+                uint16_t id,
+                const NLTypeSystem **ret_type_system,
+                size_t *ret_header_size);
 
 uint16_t type_get_type(const NLType *type);
 size_t type_get_size(const NLType *type);
 const NLTypeSystem *type_get_type_system(const NLType *type);
 const NLTypeSystemUnion *type_get_type_system_union(const NLType *type);
 
+int type_system_root_get_type_system_and_header_size(
+                sd_netlink *nl,
+                uint16_t type,
+                const NLTypeSystem **ret_type_system,
+                size_t *ret_header_size);
+
 uint16_t type_system_get_count(const NLTypeSystem *type_system);
-int type_system_root_get_type(sd_netlink *nl, const NLType **ret, uint16_t type);
 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);
 int type_system_get_type_system_union(const NLTypeSystem *type_system, const NLTypeSystemUnion **ret, uint16_t type);
index 22697aa992ea1d9cde2269fdcaa117b9743164aa..2305333575f5c4533c3d8284c609506f85057369 100644 (file)
@@ -9,6 +9,7 @@
 #include "hashmap.h"
 #include "io-util.h"
 #include "macro.h"
+#include "netlink-genl.h"
 #include "netlink-internal.h"
 #include "netlink-slot.h"
 #include "process-util.h"
@@ -196,8 +197,7 @@ static sd_netlink *netlink_free(sd_netlink *nl) {
 
         hashmap_free(nl->broadcast_group_refs);
 
-        hashmap_free(nl->genl_family_to_nlmsg_type);
-        hashmap_free(nl->nlmsg_type_to_genl_family);
+        genl_clear_family(nl);
 
         safe_close(nl->fd);
         return mfree(nl);
index a87fe1106914c4deb635116968ef91b4b38cee1b..6cc6cdad450f8815c38b60e8a3b7a95dfe3485b1 100644 (file)
@@ -9,6 +9,7 @@
 #include "alloc-util.h"
 #include "ether-addr-util.h"
 #include "macro.h"
+#include "netlink-genl.h"
 #include "netlink-internal.h"
 #include "netlink-util.h"
 #include "socket-util.h"
@@ -514,7 +515,7 @@ static void test_array(void) {
         log_debug("/* %s */", __func__);
 
         assert_se(sd_genl_socket_open(&genl) >= 0);
-        assert_se(sd_genl_message_new(genl, SD_GENL_ID_CTRL, CTRL_CMD_GETFAMILY, &m) >= 0);
+        assert_se(sd_genl_message_new(genl, CTRL_GENL_NAME, CTRL_CMD_GETFAMILY, &m) >= 0);
 
         assert_se(sd_netlink_message_open_container(m, CTRL_ATTR_MCAST_GROUPS) >= 0);
         for (unsigned i = 0; i < 10; i++) {
@@ -582,6 +583,23 @@ static void test_strv(sd_netlink *rtnl) {
         assert_se(sd_netlink_message_exit_container(m) >= 0);
 }
 
+static void test_genl(void) {
+        _cleanup_(sd_netlink_unrefp) sd_netlink *genl = NULL;
+        _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
+        const char *name;
+
+        log_debug("/* %s */", __func__);
+
+        assert_se(sd_genl_socket_open(&genl) >= 0);
+        assert_se(sd_genl_message_new(genl, CTRL_GENL_NAME, CTRL_CMD_GETFAMILY, &m) >= 0);
+        assert_se(sd_genl_message_get_family_name(genl, m, &name) >= 0);
+        assert_se(streq(name, CTRL_GENL_NAME));
+
+        m = sd_netlink_message_unref(m);
+        assert_se(sd_genl_message_new(genl, "should-not-exist", CTRL_CMD_GETFAMILY, &m) < 0);
+        assert_se(sd_genl_message_new(genl, "should-not-exist", CTRL_CMD_GETFAMILY, &m) == -EOPNOTSUPP);
+}
+
 int main(void) {
         sd_netlink *rtnl;
         sd_netlink_message *m;
@@ -642,5 +660,7 @@ int main(void) {
         assert_se((r = sd_netlink_message_unref(r)) == NULL);
         assert_se((rtnl = sd_netlink_unref(rtnl)) == NULL);
 
+        test_genl();
+
         return EXIT_SUCCESS;
 }
index 1f899e90f67abff9d02873608bb2f59e206b3df4..1d12fc79cc270d14061a2611efa5dfb4cfc91b41 100644 (file)
@@ -122,7 +122,7 @@ static int netdev_batadv_post_create(NetDev *netdev, Link *link, sd_netlink_mess
         b = BATADV(netdev);
         assert(b);
 
-        r = sd_genl_message_new(netdev->manager->genl, SD_GENL_BATADV, BATADV_CMD_SET_MESH, &message);
+        r = sd_genl_message_new(netdev->manager->genl, BATADV_NL_NAME, BATADV_CMD_SET_MESH, &message);
         if (r < 0)
                 return log_netdev_error_errno(netdev, r, "Failed to allocate generic netlink message: %m");
 
index e01de0f1510d66110f85acc044041dec76b8cc58..bc4c108a22eec0456b16fbc59a58b8bd25ad687a 100644 (file)
@@ -36,7 +36,7 @@ static int netdev_fill_fou_tunnel_message(NetDev *netdev, sd_netlink_message **r
 
         assert(t);
 
-        r = sd_genl_message_new(netdev->manager->genl, SD_GENL_FOU, FOU_CMD_ADD, &m);
+        r = sd_genl_message_new(netdev->manager->genl, FOU_GENL_NAME, FOU_CMD_ADD, &m);
         if (r < 0)
                 return log_netdev_error_errno(netdev, r, "Failed to allocate generic netlink message: %m");
 
index f651b2f7bf2c70561aab2e0fe4a6922a3f6d8f93..a04fa6ac46ad5df0edebcf9f1eb4c253a5324024 100644 (file)
@@ -104,7 +104,7 @@ static int netdev_l2tp_fill_message_tunnel(NetDev *netdev, union in_addr_union *
 
         assert(t);
 
-        r = sd_genl_message_new(netdev->manager->genl, SD_GENL_L2TP, L2TP_CMD_TUNNEL_CREATE, &m);
+        r = sd_genl_message_new(netdev->manager->genl, L2TP_GENL_NAME, L2TP_CMD_TUNNEL_CREATE, &m);
         if (r < 0)
                 return log_netdev_error_errno(netdev, r, "Failed to create generic netlink message: %m");
 
@@ -195,7 +195,7 @@ static int netdev_l2tp_fill_message_session(NetDev *netdev, L2tpSession *session
         assert(session);
         assert(session->tunnel);
 
-        r = sd_genl_message_new(netdev->manager->genl, SD_GENL_L2TP, L2TP_CMD_SESSION_CREATE, &m);
+        r = sd_genl_message_new(netdev->manager->genl, L2TP_GENL_NAME, L2TP_CMD_SESSION_CREATE, &m);
         if (r < 0)
                 return log_netdev_error_errno(netdev, r, "Failed to create generic netlink message: %m");
 
index 74e9fdd10bf68866a1c0ee1430ec58e1b7ba0bd5..3b0c9408045253805a5a2d7ee948860b356f250a 100644 (file)
@@ -224,7 +224,7 @@ static int netdev_macsec_fill_message(NetDev *netdev, int command, sd_netlink_me
         assert(netdev);
         assert(netdev->ifindex > 0);
 
-        r = sd_genl_message_new(netdev->manager->genl, SD_GENL_MACSEC, command, &m);
+        r = sd_genl_message_new(netdev->manager->genl, MACSEC_GENL_NAME, command, &m);
         if (r < 0)
                 return log_netdev_error_errno(netdev, r, "Failed to create generic netlink message: %m");
 
index b8fc492d4fcc91c881777a1ee8da39b644b5373d..1e90cad2e7129672f158c60104c79d3d7c8b6ad5 100644 (file)
@@ -229,7 +229,7 @@ static int wireguard_set_interface(NetDev *netdev) {
 
                 message = sd_netlink_message_unref(message);
 
-                r = sd_genl_message_new(netdev->manager->genl, SD_GENL_WIREGUARD, WG_CMD_SET_DEVICE, &message);
+                r = sd_genl_message_new(netdev->manager->genl, WG_GENL_NAME, WG_CMD_SET_DEVICE, &message);
                 if (r < 0)
                         return log_netdev_error_errno(netdev, r, "Failed to allocate generic netlink message: %m");
 
index f687a1a370dfcad2ca6c3b807f7a4bb39515546b..b7b536f3b542530abf311bfdbd5b1c72f305a474 100644 (file)
@@ -46,7 +46,6 @@ int main(int argc, char **argv) {
         assert_cc(sizeof(sd_lldp_event_t) == sizeof(int64_t));
         assert_cc(sizeof(sd_ndisc_event_t) == sizeof(int64_t));
         assert_cc(sizeof(sd_dhcp_lease_server_type_t) == sizeof(int64_t));
-        assert_cc(sizeof(sd_genl_family_t) == sizeof(int64_t));
 
         return EXIT_SUCCESS;
 }
index b05e1aa0df184c07ef375120b176d98568b03710..5891208076414192fcd26343078edde029e6bf56 100644 (file)
@@ -1,17 +1,18 @@
 /* SPDX-License-Identifier: LGPL-2.1-or-later */
 
 #include "log.h"
+#include "string-util.h"
 #include "wifi-util.h"
 
 int wifi_get_interface(sd_netlink *genl, int ifindex, enum nl80211_iftype *iftype, char **ssid) {
         _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL, *reply = NULL;
-        sd_genl_family_t family;
+        const char *family;
         int r;
 
         assert(genl);
         assert(ifindex > 0);
 
-        r = sd_genl_message_new(genl, SD_GENL_NL80211, NL80211_CMD_GET_INTERFACE, &m);
+        r = sd_genl_message_new(genl, NL80211_GENL_NAME, NL80211_CMD_GET_INTERFACE, &m);
         if (r < 0)
                 return log_debug_errno(r, "Failed to create generic netlink message: %m");
 
@@ -38,11 +39,11 @@ int wifi_get_interface(sd_netlink *genl, int ifindex, enum nl80211_iftype *iftyp
         if (r < 0)
                 return log_debug_errno(r, "Failed to get information about wifi interface %d: %m", ifindex);
 
-        r = sd_genl_message_get_family(genl, reply, &family);
+        r = sd_genl_message_get_family_name(genl, reply, &family);
         if (r < 0)
                 return log_debug_errno(r, "Failed to determine genl family: %m");
-        if (family != SD_GENL_NL80211) {
-                log_debug("Received message of unexpected genl family %" PRIi64 ", ignoring.", family);
+        if (!streq(family, NL80211_GENL_NAME)) {
+                log_debug("Received message of unexpected genl family '%s', ignoring.", family);
                 goto nodata;
         }
 
@@ -75,14 +76,14 @@ nodata:
 
 int wifi_get_station(sd_netlink *genl, int ifindex, struct ether_addr *bssid) {
         _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL, *reply = NULL;
-        sd_genl_family_t family;
+        const char *family;
         int r;
 
         assert(genl);
         assert(ifindex > 0);
         assert(bssid);
 
-        r = sd_genl_message_new(genl, SD_GENL_NL80211, NL80211_CMD_GET_STATION, &m);
+        r = sd_genl_message_new(genl, NL80211_GENL_NAME, NL80211_CMD_GET_STATION, &m);
         if (r < 0)
                 return log_debug_errno(r, "Failed to create generic netlink message: %m");
 
@@ -106,11 +107,11 @@ int wifi_get_station(sd_netlink *genl, int ifindex, struct ether_addr *bssid) {
         if (r < 0)
                 return log_debug_errno(r, "Failed to get information about wifi station: %m");
 
-        r = sd_genl_message_get_family(genl, reply, &family);
+        r = sd_genl_message_get_family_name(genl, reply, &family);
         if (r < 0)
                 return log_debug_errno(r, "Failed to determine genl family: %m");
-        if (family != SD_GENL_NL80211) {
-                log_debug("Received message of unexpected genl family %" PRIi64 ", ignoring.", family);
+        if (!streq(family, NL80211_GENL_NAME)) {
+                log_debug("Received message of unexpected genl family '%s', ignoring.", family);
                 goto nodata;
         }
 
index c67ea87540192f1ff696e30d0f8c3e1f55663624..6bb93fdf17af30fe28924be66438a11170159a41 100644 (file)
@@ -34,21 +34,6 @@ typedef struct sd_netlink sd_netlink;
 typedef struct sd_netlink_message sd_netlink_message;
 typedef struct sd_netlink_slot sd_netlink_slot;
 
-typedef enum sd_genl_family_t {
-        SD_GENL_ERROR,
-        SD_GENL_DONE,
-        SD_GENL_ID_CTRL,
-        SD_GENL_WIREGUARD,
-        SD_GENL_FOU,
-        SD_GENL_L2TP,
-        SD_GENL_MACSEC,
-        SD_GENL_NL80211,
-        SD_GENL_BATADV,
-        _SD_GENL_FAMILY_MAX,
-        _SD_GENL_FAMILY_INVALID = -EINVAL,
-        _SD_ENUM_FORCE_S64(GENL_FAMILY)
-} sd_genl_family_t;
-
 /* callback */
 typedef int (*sd_netlink_message_handler_t)(sd_netlink *nl, sd_netlink_message *m, void *userdata);
 typedef _sd_destroy_t sd_netlink_destroy_t;
@@ -250,8 +235,8 @@ int sd_nfnl_nft_message_add_setelem_end(sd_netlink_message *m);
 
 /* genl */
 int sd_genl_socket_open(sd_netlink **ret);
-int sd_genl_message_new(sd_netlink *genl, sd_genl_family_t family, uint8_t cmd, sd_netlink_message **ret);
-int sd_genl_message_get_family(sd_netlink *genl, sd_netlink_message *m, sd_genl_family_t *ret);
+int sd_genl_message_new(sd_netlink *genl, const char *family_name, uint8_t cmd, sd_netlink_message **ret);
+int sd_genl_message_get_family_name(sd_netlink *genl, sd_netlink_message *m, const char **ret);
 
 /* slot */
 sd_netlink_slot *sd_netlink_slot_ref(sd_netlink_slot *slot);