diff options
author | Yu Watanabe <watanabe.yu+github@gmail.com> | 2021-08-24 18:11:20 +0900 |
---|---|---|
committer | Yu Watanabe <watanabe.yu+github@gmail.com> | 2021-08-29 18:10:43 +0900 |
commit | 56fdc16da81aa1608d0ab49e76cc124a579382ec (patch) | |
tree | 342d71f264e950357fa4942df6740441feaa8676 | |
parent | 1cedca05e4fadeef0bb88fb58cf9a989ab8e6af2 (diff) | |
download | systemd-56fdc16da81aa1608d0ab49e76cc124a579382ec.tar.gz |
sd-netlink: drop sd_genl_family_t and introduce GenericNetlinkFamily
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.
-rw-r--r-- | src/libsystemd/sd-netlink/netlink-genl.c | 323 | ||||
-rw-r--r-- | src/libsystemd/sd-netlink/netlink-genl.h | 4 | ||||
-rw-r--r-- | src/libsystemd/sd-netlink/netlink-internal.h | 4 | ||||
-rw-r--r-- | src/libsystemd/sd-netlink/netlink-message.c | 38 | ||||
-rw-r--r-- | src/libsystemd/sd-netlink/netlink-socket.c | 6 | ||||
-rw-r--r-- | src/libsystemd/sd-netlink/netlink-types-genl.c | 44 | ||||
-rw-r--r-- | src/libsystemd/sd-netlink/netlink-types.c | 50 | ||||
-rw-r--r-- | src/libsystemd/sd-netlink/netlink-types.h | 14 | ||||
-rw-r--r-- | src/libsystemd/sd-netlink/sd-netlink.c | 4 | ||||
-rw-r--r-- | src/libsystemd/sd-netlink/test-netlink.c | 22 | ||||
-rw-r--r-- | src/network/netdev/batadv.c | 2 | ||||
-rw-r--r-- | src/network/netdev/fou-tunnel.c | 2 | ||||
-rw-r--r-- | src/network/netdev/l2tp-tunnel.c | 4 | ||||
-rw-r--r-- | src/network/netdev/macsec.c | 2 | ||||
-rw-r--r-- | src/network/netdev/wireguard.c | 2 | ||||
-rw-r--r-- | src/network/test-network-tables.c | 1 | ||||
-rw-r--r-- | src/shared/wifi-util.c | 21 | ||||
-rw-r--r-- | src/systemd/sd-netlink.h | 19 |
18 files changed, 363 insertions, 199 deletions
diff --git a/src/libsystemd/sd-netlink/netlink-genl.c b/src/libsystemd/sd-netlink/netlink-genl.c index 06406add49..1aeca0c5cf 100644 --- a/src/libsystemd/sd-netlink/netlink-genl.c +++ b/src/libsystemd/sd-netlink/netlink-genl.c @@ -7,154 +7,302 @@ #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); } diff --git a/src/libsystemd/sd-netlink/netlink-genl.h b/src/libsystemd/sd-netlink/netlink-genl.h index fd0461426b..b06be05952 100644 --- a/src/libsystemd/sd-netlink/netlink-genl.h +++ b/src/libsystemd/sd-netlink/netlink-genl.h @@ -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); diff --git a/src/libsystemd/sd-netlink/netlink-internal.h b/src/libsystemd/sd-netlink/netlink-internal.h index e19b460bcd..2594885fe6 100644 --- a/src/libsystemd/sd-netlink/netlink-internal.h +++ b/src/libsystemd/sd-netlink/netlink-internal.h @@ -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 { diff --git a/src/libsystemd/sd-netlink/netlink-message.c b/src/libsystemd/sd-netlink/netlink-message.c index 325c570b2e..0c9b5454b6 100644 --- a/src/libsystemd/sd-netlink/netlink-message.c +++ b/src/libsystemd/sd-netlink/netlink-message.c @@ -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) { diff --git a/src/libsystemd/sd-netlink/netlink-socket.c b/src/libsystemd/sd-netlink/netlink-socket.c index 1168f4edc0..15c2789bee 100644 --- a/src/libsystemd/sd-netlink/netlink-socket.c +++ b/src/libsystemd/sd-netlink/netlink-socket.c @@ -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; } diff --git a/src/libsystemd/sd-netlink/netlink-types-genl.c b/src/libsystemd/sd-netlink/netlink-types-genl.c index 33e80a1745..dde682f626 100644 --- a/src/libsystemd/sd-netlink/netlink-types-genl.c +++ b/src/libsystemd/sd-netlink/netlink-types-genl.c @@ -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); } diff --git a/src/libsystemd/sd-netlink/netlink-types.c b/src/libsystemd/sd-netlink/netlink-types.c index 0f17e7e8ad..7d6caf004b 100644 --- a/src/libsystemd/sd-netlink/netlink-types.c +++ b/src/libsystemd/sd-netlink/netlink-types.c @@ -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) { diff --git a/src/libsystemd/sd-netlink/netlink-types.h b/src/libsystemd/sd-netlink/netlink-types.h index baab1dbdb0..f8261b681c 100644 --- a/src/libsystemd/sd-netlink/netlink-types.h +++ b/src/libsystemd/sd-netlink/netlink-types.h @@ -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); diff --git a/src/libsystemd/sd-netlink/sd-netlink.c b/src/libsystemd/sd-netlink/sd-netlink.c index 22697aa992..2305333575 100644 --- a/src/libsystemd/sd-netlink/sd-netlink.c +++ b/src/libsystemd/sd-netlink/sd-netlink.c @@ -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); diff --git a/src/libsystemd/sd-netlink/test-netlink.c b/src/libsystemd/sd-netlink/test-netlink.c index a87fe11069..6cc6cdad45 100644 --- a/src/libsystemd/sd-netlink/test-netlink.c +++ b/src/libsystemd/sd-netlink/test-netlink.c @@ -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; } diff --git a/src/network/netdev/batadv.c b/src/network/netdev/batadv.c index 1f899e90f6..1d12fc79cc 100644 --- a/src/network/netdev/batadv.c +++ b/src/network/netdev/batadv.c @@ -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"); diff --git a/src/network/netdev/fou-tunnel.c b/src/network/netdev/fou-tunnel.c index e01de0f151..bc4c108a22 100644 --- a/src/network/netdev/fou-tunnel.c +++ b/src/network/netdev/fou-tunnel.c @@ -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"); diff --git a/src/network/netdev/l2tp-tunnel.c b/src/network/netdev/l2tp-tunnel.c index f651b2f7bf..a04fa6ac46 100644 --- a/src/network/netdev/l2tp-tunnel.c +++ b/src/network/netdev/l2tp-tunnel.c @@ -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"); diff --git a/src/network/netdev/macsec.c b/src/network/netdev/macsec.c index 74e9fdd10b..3b0c940804 100644 --- a/src/network/netdev/macsec.c +++ b/src/network/netdev/macsec.c @@ -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"); diff --git a/src/network/netdev/wireguard.c b/src/network/netdev/wireguard.c index b8fc492d4f..1e90cad2e7 100644 --- a/src/network/netdev/wireguard.c +++ b/src/network/netdev/wireguard.c @@ -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"); diff --git a/src/network/test-network-tables.c b/src/network/test-network-tables.c index f687a1a370..b7b536f3b5 100644 --- a/src/network/test-network-tables.c +++ b/src/network/test-network-tables.c @@ -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; } diff --git a/src/shared/wifi-util.c b/src/shared/wifi-util.c index b05e1aa0df..5891208076 100644 --- a/src/shared/wifi-util.c +++ b/src/shared/wifi-util.c @@ -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; } diff --git a/src/systemd/sd-netlink.h b/src/systemd/sd-netlink.h index c67ea87540..6bb93fdf17 100644 --- a/src/systemd/sd-netlink.h +++ b/src/systemd/sd-netlink.h @@ -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); |