diff options
author | Yu Watanabe <watanabe.yu+github@gmail.com> | 2021-08-29 22:37:31 +0900 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-08-29 22:37:31 +0900 |
commit | 4917c15af7c2dfe553b8e0dbf22b4fb7cec958de (patch) | |
tree | 6db870e157004b0a62f1d1416a389ae99045acf5 | |
parent | 9c53de8bc591173e27b9eccd52d0adb66d0c250b (diff) | |
parent | 98be429243ba1d0505c98c7f64f89076ed5deb85 (diff) | |
download | systemd-4917c15af7c2dfe553b8e0dbf22b4fb7cec958de.tar.gz |
Merge pull request #20057 from yuwata/sd-netlink-genl-cleanups
sd-netlink: cleanups for generic netlink
32 files changed, 2801 insertions, 2653 deletions
diff --git a/src/basic/linux/genetlink.h b/src/basic/linux/genetlink.h new file mode 100644 index 0000000000..d83f214b41 --- /dev/null +++ b/src/basic/linux/genetlink.h @@ -0,0 +1,102 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef _UAPI__LINUX_GENERIC_NETLINK_H +#define _UAPI__LINUX_GENERIC_NETLINK_H + +#include <linux/types.h> +#include <linux/netlink.h> + +#define GENL_NAMSIZ 16 /* length of family name */ + +#define GENL_MIN_ID NLMSG_MIN_TYPE +#define GENL_MAX_ID 1023 + +struct genlmsghdr { + __u8 cmd; + __u8 version; + __u16 reserved; +}; + +#define GENL_HDRLEN NLMSG_ALIGN(sizeof(struct genlmsghdr)) + +#define GENL_ADMIN_PERM 0x01 +#define GENL_CMD_CAP_DO 0x02 +#define GENL_CMD_CAP_DUMP 0x04 +#define GENL_CMD_CAP_HASPOL 0x08 +#define GENL_UNS_ADMIN_PERM 0x10 + +/* + * List of reserved static generic netlink identifiers: + */ +#define GENL_ID_CTRL NLMSG_MIN_TYPE +#define GENL_ID_VFS_DQUOT (NLMSG_MIN_TYPE + 1) +#define GENL_ID_PMCRAID (NLMSG_MIN_TYPE + 2) +/* must be last reserved + 1 */ +#define GENL_START_ALLOC (NLMSG_MIN_TYPE + 3) + +/************************************************************************** + * Controller + **************************************************************************/ + +enum { + CTRL_CMD_UNSPEC, + CTRL_CMD_NEWFAMILY, + CTRL_CMD_DELFAMILY, + CTRL_CMD_GETFAMILY, + CTRL_CMD_NEWOPS, + CTRL_CMD_DELOPS, + CTRL_CMD_GETOPS, + CTRL_CMD_NEWMCAST_GRP, + CTRL_CMD_DELMCAST_GRP, + CTRL_CMD_GETMCAST_GRP, /* unused */ + CTRL_CMD_GETPOLICY, + __CTRL_CMD_MAX, +}; + +#define CTRL_CMD_MAX (__CTRL_CMD_MAX - 1) + +enum { + CTRL_ATTR_UNSPEC, + CTRL_ATTR_FAMILY_ID, + CTRL_ATTR_FAMILY_NAME, + CTRL_ATTR_VERSION, + CTRL_ATTR_HDRSIZE, + CTRL_ATTR_MAXATTR, + CTRL_ATTR_OPS, + CTRL_ATTR_MCAST_GROUPS, + CTRL_ATTR_POLICY, + CTRL_ATTR_OP_POLICY, + CTRL_ATTR_OP, + __CTRL_ATTR_MAX, +}; + +#define CTRL_ATTR_MAX (__CTRL_ATTR_MAX - 1) + +enum { + CTRL_ATTR_OP_UNSPEC, + CTRL_ATTR_OP_ID, + CTRL_ATTR_OP_FLAGS, + __CTRL_ATTR_OP_MAX, +}; + +#define CTRL_ATTR_OP_MAX (__CTRL_ATTR_OP_MAX - 1) + +enum { + CTRL_ATTR_MCAST_GRP_UNSPEC, + CTRL_ATTR_MCAST_GRP_NAME, + CTRL_ATTR_MCAST_GRP_ID, + __CTRL_ATTR_MCAST_GRP_MAX, +}; + +enum { + CTRL_ATTR_POLICY_UNSPEC, + CTRL_ATTR_POLICY_DO, + CTRL_ATTR_POLICY_DUMP, + + __CTRL_ATTR_POLICY_DUMP_MAX, + CTRL_ATTR_POLICY_DUMP_MAX = __CTRL_ATTR_POLICY_DUMP_MAX - 1 +}; + +#define CTRL_ATTR_MCAST_GRP_MAX (__CTRL_ATTR_MCAST_GRP_MAX - 1) + + +#endif /* _UAPI__LINUX_GENERIC_NETLINK_H */ diff --git a/src/basic/meson.build b/src/basic/meson.build index 666537868b..6d755ab646 100644 --- a/src/basic/meson.build +++ b/src/basic/meson.build @@ -83,6 +83,7 @@ basic_sources = files(''' linux/can/vxcan.h linux/fib_rules.h linux/fou.h + linux/genetlink.h linux/hdlc/ioctl.h linux/if.h linux/if_addr.h diff --git a/src/libsystemd/meson.build b/src/libsystemd/meson.build index 479b81b352..8ec871f6a4 100644 --- a/src/libsystemd/meson.build +++ b/src/libsystemd/meson.build @@ -132,19 +132,23 @@ libsystemd_sources = files(''' sd-device/sd-device.c sd-hwdb/hwdb-internal.h sd-hwdb/sd-hwdb.c - sd-netlink/generic-netlink.c - sd-netlink/generic-netlink.h + sd-netlink/netlink-genl.c + sd-netlink/netlink-genl.h sd-netlink/netlink-internal.h + sd-netlink/netlink-message-nfnl.c + sd-netlink/netlink-message-rtnl.c sd-netlink/netlink-message.c sd-netlink/netlink-slot.c sd-netlink/netlink-slot.h sd-netlink/netlink-socket.c + sd-netlink/netlink-types-genl.c + sd-netlink/netlink-types-internal.h + sd-netlink/netlink-types-nfnl.c + sd-netlink/netlink-types-rtnl.c sd-netlink/netlink-types.c sd-netlink/netlink-types.h sd-netlink/netlink-util.c sd-netlink/netlink-util.h - sd-netlink/nfnl-message.c - sd-netlink/rtnl-message.c sd-netlink/sd-netlink.c sd-network/network-util.c sd-network/network-util.h diff --git a/src/libsystemd/sd-netlink/generic-netlink.c b/src/libsystemd/sd-netlink/generic-netlink.c deleted file mode 100644 index 69f1a0cef5..0000000000 --- a/src/libsystemd/sd-netlink/generic-netlink.c +++ /dev/null @@ -1,179 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ - -#include <linux/genetlink.h> - -#include "sd-netlink.h" - -#include "alloc-util.h" -#include "generic-netlink.h" -#include "netlink-internal.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 }, -}; - -int sd_genl_socket_open(sd_netlink **ret) { - return netlink_open_family(ret, NETLINK_GENERIC); -} - -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 *genl_cmd_type, *nl_type; - const NLTypeSystem *type_system; - size_t size; - int r; - - assert(nl); - assert(nl->protocol == NETLINK_GENERIC); - assert(ret); - - 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); - - *(struct genlmsghdr *) NLMSG_DATA(m->hdr) = (struct genlmsghdr) { - .cmd = cmd, - .version = genl_families[family].version, - }; - - *ret = TAKE_PTR(m); - - 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); - assert(ret); - - if (family == SD_GENL_ID_CTRL) { - *ret = GENL_ID_CTRL; - return 0; - } - - v = hashmap_get(nl->genl_family_to_nlmsg_type, INT_TO_PTR(family)); - if (v) { - *ret = PTR_TO_UINT(v); - return 0; - } - - r = genl_message_new(nl, SD_GENL_ID_CTRL, 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; - - r = sd_netlink_message_read_u16(reply, CTRL_ATTR_FAMILY_ID, &u); - if (r < 0) - return r; - - r = hashmap_ensure_put(&nl->genl_family_to_nlmsg_type, NULL, INT_TO_PTR(family), UINT_TO_PTR(u)); - if (r < 0) - return r; - - r = hashmap_ensure_put(&nl->nlmsg_type_to_genl_family, NULL, UINT_TO_PTR(u), INT_TO_PTR(family)); - if (r < 0) - return r; - - *ret = u; - return 0; -} - -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 */ - int r; - - assert_return(nl, -EINVAL); - assert_return(nl->protocol == NETLINK_GENERIC, -EINVAL); - assert_return(ret, -EINVAL); - - r = lookup_nlmsg_type(nl, family, &nlmsg_type); - if (r < 0) - return r; - - return genl_message_new(nl, family, nlmsg_type, cmd, ret); -} - -int nlmsg_type_to_genl_family(const sd_netlink *nl, uint16_t nlmsg_type, sd_genl_family_t *ret) { - void *p; - - 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; - - *ret = PTR_TO_INT(p); - } - - return 0; -} - -int sd_genl_message_get_family(sd_netlink *nl, sd_netlink_message *m, sd_genl_family_t *ret) { - uint16_t nlmsg_type; - int r; - - assert_return(nl, -EINVAL); - assert_return(nl->protocol == NETLINK_GENERIC, -EINVAL); - assert_return(m, -EINVAL); - assert_return(ret, -EINVAL); - - r = sd_netlink_message_get_type(m, &nlmsg_type); - if (r < 0) - return r; - - return nlmsg_type_to_genl_family(nl, nlmsg_type, ret); -} diff --git a/src/libsystemd/sd-netlink/generic-netlink.h b/src/libsystemd/sd-netlink/generic-netlink.h deleted file mode 100644 index fd0461426b..0000000000 --- a/src/libsystemd/sd-netlink/generic-netlink.h +++ /dev/null @@ -1,6 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -#pragma once - -#include "sd-netlink.h" - -int nlmsg_type_to_genl_family(const sd_netlink *nl, uint16_t type, sd_genl_family_t *ret); diff --git a/src/libsystemd/sd-netlink/netlink-genl.c b/src/libsystemd/sd-netlink/netlink-genl.c new file mode 100644 index 0000000000..f6f13ae239 --- /dev/null +++ b/src/libsystemd/sd-netlink/netlink-genl.c @@ -0,0 +1,473 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include <linux/genetlink.h> + +#include "sd-netlink.h" + +#include "alloc-util.h" +#include "netlink-genl.h" +#include "netlink-internal.h" +#include "netlink-types.h" + +typedef struct GenericNetlinkFamily { + sd_netlink *genl; + + const NLTypeSystem *type_system; + + uint16_t id; /* a.k.a nlmsg_type */ + char *name; + uint32_t version; + uint32_t additional_header_size; + Hashmap *multicast_group_by_name; +} GenericNetlinkFamily; + +static const GenericNetlinkFamily nlctrl_static = { + .id = GENL_ID_CTRL, + .name = (char*) CTRL_GENL_NAME, + .version = 0x01, +}; + +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); + hashmap_free(f->multicast_group_by_name); + + return mfree(f); +} + +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; + uint8_t cmd; + int r; + + assert(nl); + assert(expected_family_name); + assert(type_system); + assert(message); + assert(ret); + + 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; + + if (!streq(family_name, CTRL_GENL_NAME)) + return -EINVAL; + + r = sd_genl_message_get_command(nl, message, &cmd); + if (r < 0) + return r; + + if (cmd != CTRL_CMD_NEWFAMILY) + return -EINVAL; + + r = sd_netlink_message_read_u16(message, CTRL_ATTR_FAMILY_ID, &f->id); + if (r < 0) + return r; + + r = sd_netlink_message_read_string_strdup(message, CTRL_ATTR_FAMILY_NAME, &f->name); + if (r < 0) + return r; + + if (!streq(f->name, expected_family_name)) + return -EINVAL; + + r = sd_netlink_message_read_u32(message, CTRL_ATTR_VERSION, &f->version); + if (r < 0) + return r; + + r = sd_netlink_message_read_u32(message, CTRL_ATTR_HDRSIZE, &f->additional_header_size); + if (r < 0) + return r; + + r = sd_netlink_message_enter_container(message, CTRL_ATTR_MCAST_GROUPS); + if (r >= 0) { + for (uint16_t i = 0; i < UINT16_MAX; i++) { + _cleanup_free_ char *group_name = NULL; + uint32_t group_id; + + r = sd_netlink_message_enter_array(message, i + 1); + if (r == -ENODATA) + break; + if (r < 0) + return r; + + r = sd_netlink_message_read_u32(message, CTRL_ATTR_MCAST_GRP_ID, &group_id); + if (r < 0) + return r; + + r = sd_netlink_message_read_string_strdup(message, CTRL_ATTR_MCAST_GRP_NAME, &group_name); + if (r < 0) + return r; + + r = sd_netlink_message_exit_container(message); + if (r < 0) + return r; + + if (group_id == 0) { + log_debug("sd-netlink: received multicast group '%s' for generic netlink family '%s' with id == 0, ignoring", + group_name, f->name); + continue; + } + + r = hashmap_ensure_put(&f->multicast_group_by_name, &string_hash_ops_free, group_name, UINT32_TO_PTR(group_id)); + if (r < 0) + return r; + + TAKE_PTR(group_name); + } + + r = sd_netlink_message_exit_container(message); + if (r < 0) + return r; + } + + r = hashmap_ensure_put(&nl->genl_family_by_id, NULL, UINT_TO_PTR(f->id), f); + if (r < 0) + return r; + + 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 const NLTypeSystem *genl_family_get_type_system(const GenericNetlinkFamily *family) { + assert(family); + + if (family->type_system) + return family->type_system; + + return genl_get_type_system_by_name(family->name); +} + +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; + + assert(nl); + assert(nl->protocol == NETLINK_GENERIC); + assert(family); + assert(ret); + + type_system = genl_family_get_type_system(family); + if (!type_system) + return -EOPNOTSUPP; + + r = message_new_full(nl, family->id, type_system, + sizeof(struct genlmsghdr) + family->additional_header_size, &m); + if (r < 0) + return r; + + *(struct genlmsghdr *) NLMSG_DATA(m->hdr) = (struct genlmsghdr) { + .cmd = cmd, + .version = family->version, + }; + + *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); + + type_system = genl_get_type_system_by_name(name); + if (!type_system) + return -EOPNOTSUPP; + + r = genl_message_new(nl, ctrl, CTRL_CMD_GETFAMILY, &req); + if (r < 0) + return r; + + r = sd_netlink_message_append_string(req, CTRL_ATTR_FAMILY_NAME, name); + if (r < 0) + return r; + + r = sd_netlink_call(nl, req, 0, &reply); + if (r < 0) + return r; + + return genl_family_new(nl, name, type_system, reply, ret); +} + +static int genl_family_get_by_name(sd_netlink *nl, const char *name, const GenericNetlinkFamily **ret) { + const GenericNetlinkFamily *f, *ctrl; + int r; + + assert(nl); + assert(nl->protocol == NETLINK_GENERIC); + assert(name); + assert(ret); + + 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_family_get_by_name_internal(nl, ctrl, name, ret); +} + +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); + + f = hashmap_get(nl->genl_family_by_id, UINT_TO_PTR(id)); + if (f) { + *ret = f; + return 0; + } + + 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) { + const NLTypeSystem *t; + + t = genl_family_get_type_system(f); + if (!t) + return -EOPNOTSUPP; + + *ret_type_system = t; + } + if (ret_header_size) + *ret_header_size = sizeof(struct genlmsghdr) + f->additional_header_size; + return 0; +} + +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; + + assert_return(nl, -EINVAL); + assert_return(nl->protocol == NETLINK_GENERIC, -EINVAL); + assert_return(m, -EINVAL); + assert_return(ret, -EINVAL); + + r = sd_netlink_message_get_type(m, &nlmsg_type); + if (r < 0) + return r; + + r = genl_family_get_by_id(nl, nlmsg_type, &family); + if (r < 0) + return r; + + *ret = family->name; + return 0; +} + +int sd_genl_message_get_command(sd_netlink *nl, sd_netlink_message *m, uint8_t *ret) { + struct genlmsghdr *h; + uint16_t nlmsg_type; + size_t size; + int r; + + assert_return(nl, -EINVAL); + assert_return(nl->protocol == NETLINK_GENERIC, -EINVAL); + assert_return(m, -EINVAL); + assert_return(m->protocol == NETLINK_GENERIC, -EINVAL); + assert_return(m->hdr, -EINVAL); + assert_return(ret, -EINVAL); + + r = sd_netlink_message_get_type(m, &nlmsg_type); + if (r < 0) + return r; + + r = genl_get_type_system_and_header_size(nl, nlmsg_type, NULL, &size); + if (r < 0) + return r; + + if (m->hdr->nlmsg_len < NLMSG_LENGTH(size)) + return -EBADMSG; + + h = NLMSG_DATA(m->hdr); + + *ret = h->cmd; + return 0; +} + +static int genl_family_get_multicast_group_id_by_name(const GenericNetlinkFamily *f, const char *name, uint32_t *ret) { + void *p; + + assert(f); + assert(name); + + p = hashmap_get(f->multicast_group_by_name, name); + if (!p) + return -ENOENT; + + if (ret) + *ret = PTR_TO_UINT32(p); + return 0; +} + +int sd_genl_add_match( + sd_netlink *nl, + sd_netlink_slot **ret_slot, + const char *family_name, + const char *multicast_group_name, + uint8_t command, + sd_netlink_message_handler_t callback, + sd_netlink_destroy_t destroy_callback, + void *userdata, + const char *description) { + + const GenericNetlinkFamily *f; + uint32_t multicast_group_id; + int r; + + assert_return(nl, -EINVAL); + assert_return(nl->protocol == NETLINK_GENERIC, -EINVAL); + assert_return(callback, -EINVAL); + assert_return(family_name, -EINVAL); + assert_return(multicast_group_name, -EINVAL); + + /* If command == 0, then all commands belonging to the multicast group trigger the callback. */ + + r = genl_family_get_by_name(nl, family_name, &f); + if (r < 0) + return r; + + r = genl_family_get_multicast_group_id_by_name(f, multicast_group_name, &multicast_group_id); + if (r < 0) + return r; + + return netlink_add_match_internal(nl, ret_slot, &multicast_group_id, 1, f->id, command, + callback, destroy_callback, userdata, description); +} + +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 new file mode 100644 index 0000000000..b06be05952 --- /dev/null +++ b/src/libsystemd/sd-netlink/netlink-genl.h @@ -0,0 +1,8 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +#include "sd-netlink.h" + +#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 49c7dd773d..050edaec78 100644 --- a/src/libsystemd/sd-netlink/netlink-internal.h +++ b/src/libsystemd/sd-netlink/netlink-internal.h @@ -10,11 +10,11 @@ #include "prioq.h" #include "time-util.h" -#define RTNL_DEFAULT_TIMEOUT ((usec_t) (25 * USEC_PER_SEC)) +#define NETLINK_DEFAULT_TIMEOUT_USEC ((usec_t) (25 * USEC_PER_SEC)) -#define RTNL_RQUEUE_MAX 64*1024 +#define NETLINK_RQUEUE_MAX 64*1024 -#define RTNL_CONTAINER_DEPTH 32 +#define NETLINK_CONTAINER_DEPTH 32 struct reply_callback { sd_netlink_message_handler_t callback; @@ -25,7 +25,10 @@ struct reply_callback { struct match_callback { sd_netlink_message_handler_t callback; + uint32_t *groups; + size_t n_groups; uint16_t type; + uint8_t cmd; /* used by genl */ LIST_FIELDS(struct match_callback, match_callbacks); }; @@ -95,8 +98,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 { @@ -118,7 +121,7 @@ struct sd_netlink_message { int protocol; struct nlmsghdr *hdr; - struct netlink_container containers[RTNL_CONTAINER_DEPTH]; + struct netlink_container containers[NETLINK_CONTAINER_DEPTH]; unsigned n_containers; /* number of containers */ bool sealed:1; bool broadcast:1; @@ -126,10 +129,22 @@ struct sd_netlink_message { sd_netlink_message *next; /* next in a chain of multi-part messages */ }; -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 message_new_empty(sd_netlink *nl, sd_netlink_message **ret); +int message_new_full( + sd_netlink *nl, + uint16_t nlmsg_type, + const NLTypeSystem *type_system, + size_t header_size, + sd_netlink_message **ret); +int message_new(sd_netlink *nl, sd_netlink_message **ret, uint16_t type); +int message_new_synthetic_error(sd_netlink *nl, int error, uint32_t serial, sd_netlink_message **ret); +uint32_t message_get_serial(sd_netlink_message *m); +void message_seal(sd_netlink_message *m); int netlink_open_family(sd_netlink **ret, int family); +bool netlink_pid_changed(sd_netlink *nl); +int netlink_rqueue_make_room(sd_netlink *nl); +int netlink_rqueue_partial_make_room(sd_netlink *nl); int socket_open(int family); int socket_bind(sd_netlink *nl); @@ -139,9 +154,18 @@ int socket_write_message(sd_netlink *nl, sd_netlink_message *m); int socket_writev_message(sd_netlink *nl, sd_netlink_message **m, size_t msgcount); int socket_read_message(sd_netlink *nl); -int rtnl_rqueue_make_room(sd_netlink *rtnl); -int rtnl_rqueue_partial_make_room(sd_netlink *rtnl); - -/* Make sure callbacks don't destroy the rtnl connection */ -#define NETLINK_DONT_DESTROY(rtnl) \ - _cleanup_(sd_netlink_unrefp) _unused_ sd_netlink *_dont_destroy_##rtnl = sd_netlink_ref(rtnl) +int netlink_add_match_internal( + sd_netlink *nl, + sd_netlink_slot **ret_slot, + const uint32_t *groups, + size_t n_groups, + uint16_t type, + uint8_t cmd, + sd_netlink_message_handler_t callback, + sd_netlink_destroy_t destroy_callback, + void *userdata, + const char *description); + +/* Make sure callbacks don't destroy the netlink connection */ +#define NETLINK_DONT_DESTROY(nl) \ + _cleanup_(sd_netlink_unrefp) _unused_ sd_netlink *_dont_destroy_##nl = sd_netlink_ref(nl) diff --git a/src/libsystemd/sd-netlink/nfnl-message.c b/src/libsystemd/sd-netlink/netlink-message-nfnl.c index 5f669f750b..9b24f74042 100644 --- a/src/libsystemd/sd-netlink/nfnl-message.c +++ b/src/libsystemd/sd-netlink/netlink-message-nfnl.c @@ -13,48 +13,20 @@ #include "format-util.h" #include "netlink-internal.h" #include "netlink-types.h" -#include "netlink-util.h" #include "socket-util.h" -#include "util.h" -static int nft_message_new(sd_netlink *nfnl, sd_netlink_message **ret, int family, uint16_t type, uint16_t flags) { +static int nft_message_new(sd_netlink *nfnl, sd_netlink_message **ret, int family, uint16_t msg_type, uint16_t flags) { _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; - const NLType *nl_type; - size_t size; int r; assert_return(nfnl, -EINVAL); + assert_return(ret, -EINVAL); - r = type_system_root_get_type(nfnl, &nl_type, NFNL_SUBSYS_NFTABLES); + r = message_new(nfnl, &m, NFNL_SUBSYS_NFTABLES << 8 | msg_type); if (r < 0) return r; - if (type_get_type(nl_type) != NETLINK_TYPE_NESTED) - return -EINVAL; - - r = message_new_empty(nfnl, &m); - if (r < 0) - return r; - - size = NLMSG_SPACE(type_get_size(nl_type)); - - assert(size >= sizeof(struct nlmsghdr)); - m->hdr = malloc0(size); - if (!m->hdr) - return -ENOMEM; - - m->hdr->nlmsg_flags = NLM_F_REQUEST | flags; - - type_get_type_system(nl_type, &m->containers[0].type_system); - - r = type_system_get_type_system(m->containers[0].type_system, - &m->containers[0].type_system, - type); - if (r < 0) - return r; - - m->hdr->nlmsg_len = size; - m->hdr->nlmsg_type = NFNL_SUBSYS_NFTABLES << 8 | type; + m->hdr->nlmsg_flags |= flags; *(struct nfgenmsg*) NLMSG_DATA(m->hdr) = (struct nfgenmsg) { .nfgen_family = family, @@ -66,11 +38,11 @@ static int nft_message_new(sd_netlink *nfnl, sd_netlink_message **ret, int famil return 0; } -static int sd_nfnl_message_batch(sd_netlink *nfnl, sd_netlink_message **ret, int v) { +static int nfnl_message_batch(sd_netlink *nfnl, sd_netlink_message **ret, uint16_t msg_type) { _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; int r; - r = message_new(nfnl, &m, v); + r = message_new(nfnl, &m, NFNL_SUBSYS_NONE << 8 | msg_type); if (r < 0) return r; @@ -81,26 +53,31 @@ static int sd_nfnl_message_batch(sd_netlink *nfnl, sd_netlink_message **ret, int }; *ret = TAKE_PTR(m); - return r; + return 0; } int sd_nfnl_message_batch_begin(sd_netlink *nfnl, sd_netlink_message **ret) { - return sd_nfnl_message_batch(nfnl, ret, NFNL_MSG_BATCH_BEGIN); + return nfnl_message_batch(nfnl, ret, NFNL_MSG_BATCH_BEGIN); } int sd_nfnl_message_batch_end(sd_netlink *nfnl, sd_netlink_message **ret) { - return sd_nfnl_message_batch(nfnl, ret, NFNL_MSG_BATCH_END); + return nfnl_message_batch(nfnl, ret, NFNL_MSG_BATCH_END); } -int sd_nfnl_nft_message_new_basechain(sd_netlink *nfnl, sd_netlink_message **ret, - int family, - const char *table, const char *chain, - const char *type, - uint8_t hook, int prio) { +int sd_nfnl_nft_message_new_basechain( + sd_netlink *nfnl, + sd_netlink_message **ret, + int family, + const char *table, + const char *chain, + const char *type, + uint8_t hook, + int prio) { + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; int r; - r = nft_message_new(nfnl, &m, family, NFT_MSG_NEWCHAIN, NLM_F_CREATE | NLM_F_ACK); + r = nft_message_new(nfnl, &m, family, NFT_MSG_NEWCHAIN, NLM_F_CREATE); if (r < 0) return r; @@ -136,12 +113,16 @@ int sd_nfnl_nft_message_new_basechain(sd_netlink *nfnl, sd_netlink_message **ret return 0; } -int sd_nfnl_nft_message_del_table(sd_netlink *nfnl, sd_netlink_message **ret, - int family, const char *table) { +int sd_nfnl_nft_message_del_table( + sd_netlink *nfnl, + sd_netlink_message **ret, + int family, + const char *table) { + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; int r; - r = nft_message_new(nfnl, &m, family, NFT_MSG_DELTABLE, NLM_F_CREATE | NLM_F_ACK); + r = nft_message_new(nfnl, &m, family, NFT_MSG_DELTABLE, NLM_F_CREATE); if (r < 0) return r; @@ -153,12 +134,16 @@ int sd_nfnl_nft_message_del_table(sd_netlink *nfnl, sd_netlink_message **ret, return r; } -int sd_nfnl_nft_message_new_table(sd_netlink *nfnl, sd_netlink_message **ret, - int family, const char *table, uint16_t flags) { +int sd_nfnl_nft_message_new_table( + sd_netlink *nfnl, + sd_netlink_message **ret, + int family, + const char *table) { + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; int r; - r = nft_message_new(nfnl, &m, family, NFT_MSG_NEWTABLE, NLM_F_CREATE | flags); + r = nft_message_new(nfnl, &m, family, NFT_MSG_NEWTABLE, NLM_F_CREATE | NLM_F_EXCL); if (r < 0) return r; @@ -170,12 +155,17 @@ int sd_nfnl_nft_message_new_table(sd_netlink *nfnl, sd_netlink_message **ret, return r; } -int sd_nfnl_nft_message_new_rule(sd_netlink *nfnl, sd_netlink_message **ret, - int family, const char *table, const char *chain) { +int sd_nfnl_nft_message_new_rule( + sd_netlink *nfnl, + sd_netlink_message **ret, + int family, + const char *table, + const char *chain) { + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; int r; - r = nft_message_new(nfnl, &m, family, NFT_MSG_NEWRULE, NLM_F_CREATE | NLM_F_ACK); + r = nft_message_new(nfnl, &m, family, NFT_MSG_NEWRULE, NLM_F_CREATE); if (r < 0) return r; @@ -191,13 +181,19 @@ int sd_nfnl_nft_message_new_rule(sd_netlink *nfnl, sd_netlink_message **ret, return r; } -int sd_nfnl_nft_message_new_set(sd_netlink *nfnl, sd_netlink_message **ret, - int family, const char *table, const char *set_name, - uint32_t set_id, uint32_t klen) { +int sd_nfnl_nft_message_new_set( + sd_netlink *nfnl, + sd_netlink_message **ret, + int family, + const char *table, + const char *set_name, + uint32_t set_id, + uint32_t klen) { + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; int r; - r = nft_message_new(nfnl, &m, family, NFT_MSG_NEWSET, NLM_F_CREATE | NLM_F_ACK); + r = nft_message_new(nfnl, &m, family, NFT_MSG_NEWSET, NLM_F_CREATE); if (r < 0) return r; @@ -216,16 +212,22 @@ int sd_nfnl_nft_message_new_set(sd_netlink *nfnl, sd_netlink_message **ret, r = sd_netlink_message_append_u32(m, NFTA_SET_KEY_LEN, htobe32(klen)); if (r < 0) return r; + *ret = TAKE_PTR(m); return r; } -int sd_nfnl_nft_message_new_setelems_begin(sd_netlink *nfnl, sd_netlink_message **ret, - int family, const char *table, const char *set_name) { +int sd_nfnl_nft_message_new_setelems_begin( + sd_netlink *nfnl, + sd_netlink_message **ret, + int family, + const char *table, + const char *set_name) { + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; int r; - r = nft_message_new(nfnl, &m, family, NFT_MSG_NEWSETELEM, NLM_F_CREATE | NLM_F_ACK); + r = nft_message_new(nfnl, &m, family, NFT_MSG_NEWSETELEM, NLM_F_CREATE); if (r < 0) return r; @@ -245,12 +247,17 @@ int sd_nfnl_nft_message_new_setelems_begin(sd_netlink *nfnl, sd_netlink_message return r; } -int sd_nfnl_nft_message_del_setelems_begin(sd_netlink *nfnl, sd_netlink_message **ret, - int family, const char *table, const char *set_name) { +int sd_nfnl_nft_message_del_setelems_begin( + sd_netlink *nfnl, + sd_netlink_message **ret, + int family, + const char *table, + const char *set_name) { + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; int r; - r = nft_message_new(nfnl, &m, family, NFT_MSG_DELSETELEM, NLM_F_ACK); + r = nft_message_new(nfnl, &m, family, NFT_MSG_DELSETELEM, 0); if (r < 0) return r; @@ -271,7 +278,9 @@ int sd_nfnl_nft_message_del_setelems_begin(sd_netlink *nfnl, sd_netlink_message } static int sd_nfnl_add_data(sd_netlink_message *m, uint16_t attr, const void *data, uint32_t dlen) { - int r = sd_netlink_message_open_container(m, attr); + int r; + + r = sd_netlink_message_open_container(m, attr); if (r < 0) return r; @@ -282,9 +291,14 @@ static int sd_nfnl_add_data(sd_netlink_message *m, uint16_t attr, const void *da return sd_netlink_message_close_container(m); /* attr */ } -int sd_nfnl_nft_message_add_setelem(sd_netlink_message *m, uint32_t num, - const void *key, uint32_t klen, - const void *data, uint32_t dlen) { +int sd_nfnl_nft_message_add_setelem( + sd_netlink_message *m, + uint32_t num, + const void *key, + uint32_t klen, + const void *data, + uint32_t dlen) { + int r; r = sd_netlink_message_open_array(m, num); @@ -301,7 +315,8 @@ int sd_nfnl_nft_message_add_setelem(sd_netlink_message *m, uint32_t num, goto cancel; } - return r; + return 0; + cancel: sd_netlink_message_cancel_array(m); return r; diff --git a/src/libsystemd/sd-netlink/rtnl-message.c b/src/libsystemd/sd-netlink/netlink-message-rtnl.c index 9127167bb2..313857699a 100644 --- a/src/libsystemd/sd-netlink/rtnl-message.c +++ b/src/libsystemd/sd-netlink/netlink-message-rtnl.c @@ -271,13 +271,13 @@ int sd_rtnl_message_new_route(sd_netlink *rtnl, sd_netlink_message **ret, } int sd_rtnl_message_new_nexthop(sd_netlink *rtnl, sd_netlink_message **ret, - uint16_t nhmsg_type, int nh_family, + uint16_t nlmsg_type, int nh_family, unsigned char nh_protocol) { struct nhmsg *nhm; int r; - assert_return(rtnl_message_type_is_nexthop(nhmsg_type), -EINVAL); - switch(nhmsg_type) { + assert_return(rtnl_message_type_is_nexthop(nlmsg_type), -EINVAL); + switch(nlmsg_type) { case RTM_DELNEXTHOP: assert_return(nh_family == AF_UNSPEC, -EINVAL); _fallthrough_; @@ -292,11 +292,11 @@ int sd_rtnl_message_new_nexthop(sd_netlink *rtnl, sd_netlink_message **ret, } assert_return(ret, -EINVAL); - r = message_new(rtnl, ret, nhmsg_type); + r = message_new(rtnl, ret, nlmsg_type); if (r < 0) return r; - if (nhmsg_type == RTM_NEWNEXTHOP) + if (nlmsg_type == RTM_NEWNEXTHOP) (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_APPEND; nhm = NLMSG_DATA((*ret)->hdr); diff --git a/src/libsystemd/sd-netlink/netlink-message.c b/src/libsystemd/sd-netlink/netlink-message.c index c4dc4e67dd..e422d5699c 100644 --- a/src/libsystemd/sd-netlink/netlink-message.c +++ b/src/libsystemd/sd-netlink/netlink-message.c @@ -20,15 +20,14 @@ #define RTA_TYPE(rta) ((rta)->rta_type & NLA_TYPE_MASK) #define RTA_FLAGS(rta) ((rta)->rta_type & ~NLA_TYPE_MASK) -int message_new_empty(sd_netlink *rtnl, sd_netlink_message **ret) { +int message_new_empty(sd_netlink *nl, sd_netlink_message **ret) { sd_netlink_message *m; - assert_return(ret, -EINVAL); + assert(nl); + assert(ret); - /* Note that 'rtnl' is currently unused, if we start using it internally - we must take care to avoid problems due to mutual references between - buses and their queued messages. See sd-bus. - */ + /* Note that 'nl' is currently unused, if we start using it internally we must take care to + * avoid problems due to mutual references between buses and their queued messages. See sd-bus. */ m = new(sd_netlink_message, 1); if (!m) @@ -36,48 +35,80 @@ int message_new_empty(sd_netlink *rtnl, sd_netlink_message **ret) { *m = (sd_netlink_message) { .n_ref = 1, - .protocol = rtnl->protocol, + .protocol = nl->protocol, .sealed = false, }; *ret = m; - return 0; } -int message_new(sd_netlink *rtnl, sd_netlink_message **ret, uint16_t type) { +int message_new_full( + sd_netlink *nl, + uint16_t nlmsg_type, + const NLTypeSystem *type_system, + size_t header_size, + sd_netlink_message **ret) { + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; - const NLType *nl_type; size_t size; int r; - assert_return(rtnl, -EINVAL); + assert(nl); + assert(type_system); + assert(ret); - r = type_system_root_get_type(rtnl, &nl_type, type); - if (r < 0) - return r; - - if (type_get_type(nl_type) != NETLINK_TYPE_NESTED) - return -EINVAL; + size = NLMSG_SPACE(header_size); + assert(size >= sizeof(struct nlmsghdr)); - r = message_new_empty(rtnl, &m); + r = message_new_empty(nl, &m); if (r < 0) return r; - size = NLMSG_SPACE(type_get_size(nl_type)); + m->containers[0].type_system = type_system; - assert(size >= sizeof(struct nlmsghdr)); m->hdr = malloc0(size); if (!m->hdr) return -ENOMEM; m->hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; - - type_get_type_system(nl_type, &m->containers[0].type_system); m->hdr->nlmsg_len = size; - m->hdr->nlmsg_type = type; + m->hdr->nlmsg_type = nlmsg_type; *ret = TAKE_PTR(m); + return 0; +} + +int message_new(sd_netlink *nl, sd_netlink_message **ret, uint16_t type) { + const NLTypeSystem *type_system; + size_t size; + int r; + + assert_return(nl, -EINVAL); + assert_return(ret, -EINVAL); + + r = type_system_root_get_type_system_and_header_size(nl, type, &type_system, &size); + if (r < 0) + return r; + + 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) { + struct nlmsgerr *err; + int r; + + assert(error <= 0); + + r = message_new(nl, ret, NLMSG_ERROR); + if (r < 0) + return r; + + message_seal(*ret); + (*ret)->hdr->nlmsg_seq = serial; + + err = NLMSG_DATA((*ret)->hdr); + err->error = error; return 0; } @@ -184,13 +215,12 @@ static int add_rtattr(sd_netlink_message *m, unsigned short type, const void *da static int message_attribute_has_type(sd_netlink_message *m, size_t *out_size, uint16_t attribute_type, uint16_t data_type) { const NLType *type; - int r; assert(m); - r = type_system_get_type(m->containers[m->n_containers].type_system, &type, attribute_type); - if (r < 0) - return r; + type = type_system_get_type(m->containers[m->n_containers].type_system, attribute_type); + if (!type) + return -EOPNOTSUPP; if (type_get_type(type) != data_type) return -EINVAL; @@ -538,7 +568,7 @@ int sd_netlink_message_open_container(sd_netlink_message *m, unsigned short type assert_return(m, -EINVAL); assert_return(!m->sealed, -EPERM); /* m->containers[m->n_containers + 1] is accessed both in read and write. Prevent access out of bound */ - assert_return(m->n_containers < (RTNL_CONTAINER_DEPTH - 1), -ERANGE); + assert_return(m->n_containers < (NETLINK_CONTAINER_DEPTH - 1), -ERANGE); r = message_attribute_has_type(m, &size, type, NETLINK_TYPE_NESTED); if (r < 0) { @@ -553,22 +583,23 @@ int sd_netlink_message_open_container(sd_netlink_message *m, unsigned short type if (r < 0) return r; - r = type_system_get_type_system_union(m->containers[m->n_containers].type_system, &type_system_union, type); - if (r < 0) - return r; + type_system_union = type_system_get_type_system_union( + m->containers[m->n_containers].type_system, + type); + if (!type_system_union) + return -EOPNOTSUPP; - r = type_system_union_protocol_get_type_system(type_system_union, - &m->containers[m->n_containers + 1].type_system, - family); - if (r < 0) - return r; - } else { - r = type_system_get_type_system(m->containers[m->n_containers].type_system, - &m->containers[m->n_containers + 1].type_system, - type); - if (r < 0) - return r; - } + m->containers[m->n_containers + 1].type_system = + type_system_union_get_type_system_by_protocol( + type_system_union, + family); + } else + m->containers[m->n_containers + 1].type_system = + type_system_get_type_system( + m->containers[m->n_containers].type_system, + type); + if (!m->containers[m->n_containers + 1].type_system) + return -EOPNOTSUPP; r = add_rtattr(m, type | NLA_F_NESTED, NULL, size); if (r < 0) @@ -585,19 +616,22 @@ int sd_netlink_message_open_container_union(sd_netlink_message *m, unsigned shor assert_return(m, -EINVAL); assert_return(!m->sealed, -EPERM); - assert_return(m->n_containers < (RTNL_CONTAINER_DEPTH - 1), -ERANGE); + assert_return(m->n_containers < (NETLINK_CONTAINER_DEPTH - 1), -ERANGE); - r = type_system_get_type_system_union(m->containers[m->n_containers].type_system, &type_system_union, type); - if (r < 0) - return r; + type_system_union = type_system_get_type_system_union( + m->containers[m->n_containers].type_system, + type); + if (!type_system_union) + return -EOPNOTSUPP; - r = type_system_union_get_type_system(type_system_union, - &m->containers[m->n_containers + 1].type_system, - key); - if (r < 0) - return r; + m->containers[m->n_containers + 1].type_system = + type_system_union_get_type_system_by_string( + type_system_union, + key); + if (!m->containers[m->n_containers + 1].type_system) + return -EOPNOTSUPP; - r = sd_netlink_message_append_string(m, type_system_union->match, key); + r = sd_netlink_message_append_string(m, type_system_union_get_match_attribute(type_system_union), key); if (r < 0) return r; @@ -628,7 +662,7 @@ int sd_netlink_message_open_array(sd_netlink_message *m, uint16_t type) { assert_return(m, -EINVAL); assert_return(!m->sealed, -EPERM); - assert_return(m->n_containers < (RTNL_CONTAINER_DEPTH - 1), -ERANGE); + assert_return(m->n_containers < (NETLINK_CONTAINER_DEPTH - 1), -ERANGE); r = add_rtattr(m, type | NLA_F_NESTED, NULL, 0); if (r < 0) @@ -673,7 +707,7 @@ static int netlink_message_read_internal( assert_return(m, -EINVAL); assert_return(m->sealed, -EPERM); - assert(m->n_containers < RTNL_CONTAINER_DEPTH); + assert(m->n_containers < NETLINK_CONTAINER_DEPTH); if (!m->containers[m->n_containers].attributes) return -ENODATA; @@ -1008,26 +1042,26 @@ int sd_netlink_message_read_strv(sd_netlink_message *m, unsigned short container int r; assert_return(m, -EINVAL); - assert_return(m->n_containers < RTNL_CONTAINER_DEPTH, -EINVAL); + assert_return(m->n_containers < NETLINK_CONTAINER_DEPTH, -EINVAL); - r = type_system_get_type(m->containers[m->n_containers].type_system, - &nl_type, - container_type); - if (r < 0) - return r; + nl_type = type_system_get_type( + m->containers[m->n_containers].type_system, + container_type); + if (!nl_type) + return -EOPNOTSUPP; if (type_get_type(nl_type) != NETLINK_TYPE_NESTED) return -EINVAL; - r = type_system_get_type_system(m->containers[m->n_containers].type_system, - &type_system, - container_type); - if (r < 0) - return r; + type_system = type_system_get_type_system( + m->containers[m->n_containers].type_system, + container_type); + if (!type_system) + return -EOPNOTSUPP; - r = type_system_get_type(type_system, &nl_type, type_id); - if (r < 0) - return r; + nl_type = type_system_get_type(type_system, type_id); + if (!nl_type) + return -EOPNOTSUPP; if (type_get_type(nl_type) != NETLINK_TYPE_STRING) return -EINVAL; @@ -1079,7 +1113,7 @@ static int netlink_container_parse(sd_netlink_message *m, return -ENOMEM; if (attributes[type].offset != 0) - log_debug("rtnl: message parse - overwriting repeated attribute"); + log_debug("sd-netlink: message parse - overwriting repeated attribute"); attributes[type].offset = (uint8_t *) rta - (uint8_t *) m->hdr; attributes[type].nested = RTA_FLAGS(rta) & NLA_F_NESTED; @@ -1104,61 +1138,62 @@ int sd_netlink_message_enter_container(sd_netlink_message *m, unsigned short typ int r; assert_return(m, -EINVAL); - assert_return(m->n_containers < (RTNL_CONTAINER_DEPTH - 1), -EINVAL); + assert_return(m->n_containers < (NETLINK_CONTAINER_DEPTH - 1), -EINVAL); - r = type_system_get_type(m->containers[m->n_containers].type_system, - &nl_type, - type_id); - if (r < 0) - return r; + nl_type = type_system_get_type( + m->containers[m->n_containers].type_system, + type_id); + if (!nl_type) + return -EOPNOTSUPP; type = type_get_type(nl_type); if (type == NETLINK_TYPE_NESTED) { - r = type_system_get_type_system(m->containers[m->n_containers].type_system, - &type_system, - type_id); - if (r < 0) - return r; + type_system = type_system_get_type_system( + m->containers[m->n_containers].type_system, + type_id); + if (!type_system) + return -EOPNOTSUPP; } else if (type == NETLINK_TYPE_UNION) { const NLTypeSystemUnion *type_system_union; - r = type_system_get_type_system_union(m->containers[m->n_containers].type_system, - &type_system_union, - type_id); - if (r < 0) - return r; + type_system_union = type_system_get_type_system_union( + m->containers[m->n_containers].type_system, + type_id); + if (!type_system_union) + return -EOPNOTSUPP; - switch (type_system_union->match_type) { - case NL_MATCH_SIBLING: - { + switch (type_system_union_get_match_type(type_system_union)) { + case NL_MATCH_SIBLING: { const char *key; - r = sd_netlink_message_read_string(m, type_system_union->match, &key); + r = sd_netlink_message_read_string( + m, + type_system_union_get_match_attribute(type_system_union), + &key); if (r < 0) return r; - r = type_system_union_get_type_system(type_system_union, - &type_system, - key); - if (r < 0) - return r; + type_system = type_system_union_get_type_system_by_string( + type_system_union, + key); + if (!type_system) + return -EOPNOTSUPP; break; } - case NL_MATCH_PROTOCOL: - { + case NL_MATCH_PROTOCOL: { int family; r = sd_rtnl_message_get_family(m, &family); if (r < 0) return r; - r = type_system_union_protocol_get_type_system(type_system_union, - &type_system, - family); - if (r < 0) - return r; + type_system = type_system_union_get_type_system_by_protocol( + type_system_union, + family); + if (!type_system) + return -EOPNOTSUPP; break; } @@ -1195,7 +1230,7 @@ int sd_netlink_message_enter_array(sd_netlink_message *m, unsigned short type_id int r; assert_return(m, -EINVAL); - assert_return(m->n_containers < (RTNL_CONTAINER_DEPTH - 1), -EINVAL); + assert_return(m->n_containers < (NETLINK_CONTAINER_DEPTH - 1), -EINVAL); r = netlink_message_read_internal(m, type_id, &container, NULL); if (r < 0) @@ -1231,7 +1266,7 @@ int sd_netlink_message_exit_container(sd_netlink_message *m) { return 0; } -uint32_t rtnl_message_get_serial(sd_netlink_message *m) { +uint32_t message_get_serial(sd_netlink_message *m) { assert(m); assert(m->hdr); @@ -1280,18 +1315,15 @@ static int netlink_message_parse_error(sd_netlink_message *m) { NLMSG_PAYLOAD(m->hdr, hlen)); } -int sd_netlink_message_rewind(sd_netlink_message *m, sd_netlink *genl) { - const NLType *nl_type; - uint16_t type; +int sd_netlink_message_rewind(sd_netlink_message *m, sd_netlink *nl) { size_t size; int r; assert_return(m, -EINVAL); - assert_return(genl || m->protocol != NETLINK_GENERIC, -EINVAL); + assert_return(nl, -EINVAL); /* don't allow appending to message once parsed */ - if (!m->sealed) - rtnl_message_seal(m); + message_seal(m); for (unsigned i = 1; i <= m->n_containers; i++) m->containers[i].attributes = mfree(m->containers[i].attributes); @@ -1304,37 +1336,22 @@ int sd_netlink_message_rewind(sd_netlink_message *m, sd_netlink *genl) { assert(m->hdr); - r = type_system_root_get_type(genl, &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) { - const NLTypeSystem *type_system; - - type_get_type_system(nl_type, &type_system); - - m->containers[0].type_system = type_system; - - 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; - } + if (sd_netlink_message_is_error(m)) + return netlink_message_parse_error(m); - 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 rtnl_message_seal(sd_netlink_message *m) { +void message_seal(sd_netlink_message *m) { assert(m); - assert(!m->sealed); m->sealed = true; } diff --git a/src/libsystemd/sd-netlink/netlink-slot.c b/src/libsystemd/sd-netlink/netlink-slot.c index 76b4ccaa96..34f527d07f 100644 --- a/src/libsystemd/sd-netlink/netlink-slot.c +++ b/src/libsystemd/sd-netlink/netlink-slot.c @@ -70,25 +70,11 @@ void netlink_slot_disconnect(sd_netlink_slot *slot, bool unref) { case NETLINK_MATCH_CALLBACK: LIST_REMOVE(match_callbacks, nl->match_callbacks, &slot->match_callback); - switch (slot->match_callback.type) { - case RTM_NEWLINK: - case RTM_DELLINK: - (void) socket_broadcast_group_unref(nl, RTNLGRP_LINK); - - break; - case RTM_NEWADDR: - case RTM_DELADDR: - (void) socket_broadcast_group_unref(nl, RTNLGRP_IPV4_IFADDR); - (void) socket_broadcast_group_unref(nl, RTNLGRP_IPV6_IFADDR); - - break; - case RTM_NEWROUTE: - case RTM_DELROUTE: - (void) socket_broadcast_group_unref(nl, RTNLGRP_IPV4_ROUTE); - (void) socket_broadcast_group_unref(nl, RTNLGRP_IPV6_ROUTE); - - break; - } + for (size_t i = 0; i < slot->match_callback.n_groups; i++) + (void) socket_broadcast_group_unref(nl, slot->match_callback.groups[i]); + + slot->match_callback.n_groups = 0; + slot->match_callback.groups = mfree(slot->match_callback.groups); break; default: diff --git a/src/libsystemd/sd-netlink/netlink-socket.c b/src/libsystemd/sd-netlink/netlink-socket.c index 21ec00cca0..15c2789bee 100644 --- a/src/libsystemd/sd-netlink/netlink-socket.c +++ b/src/libsystemd/sd-netlink/netlink-socket.c @@ -238,7 +238,7 @@ static int socket_recv_message(int fd, struct iovec *iov, uint32_t *ret_mcast_gr n = recvmsg_safe(fd, &msg, MSG_TRUNC | (peek ? MSG_PEEK : 0)); if (n == -ENOBUFS) - return log_debug_errno(n, "rtnl: kernel receive buffer overrun"); + return log_debug_errno(n, "sd-netlink: kernel receive buffer overrun"); if (IN_SET(n, -EAGAIN, -EINTR)) return 0; if (n < 0) @@ -246,7 +246,7 @@ static int socket_recv_message(int fd, struct iovec *iov, uint32_t *ret_mcast_gr if (sender.nl.nl_pid != 0) { /* not from the kernel, ignore */ - log_debug("rtnl: ignoring message from PID %"PRIu32, sender.nl.nl_pid); + log_debug("sd-netlink: ignoring message from PID %"PRIu32, sender.nl.nl_pid); if (peek) { /* drop the message */ @@ -276,7 +276,7 @@ static int socket_recv_message(int fd, struct iovec *iov, uint32_t *ret_mcast_gr * If nothing useful was received 0 is returned. * On failure, a negative error code is returned. */ -int socket_read_message(sd_netlink *rtnl) { +int socket_read_message(sd_netlink *nl) { _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *first = NULL; bool multi_part = false, done = false; size_t len, allocated; @@ -285,25 +285,25 @@ int socket_read_message(sd_netlink *rtnl) { unsigned i = 0; int r; - assert(rtnl); - assert(rtnl->rbuffer); + assert(nl); + assert(nl->rbuffer); /* read nothing, just get the pending message size */ - r = socket_recv_message(rtnl->fd, &iov, NULL, true); + r = socket_recv_message(nl->fd, &iov, NULL, true); if (r <= 0) return r; else len = (size_t) r; /* make room for the pending message */ - if (!greedy_realloc((void **)&rtnl->rbuffer, len, sizeof(uint8_t))) + if (!greedy_realloc((void**) &nl->rbuffer, len, sizeof(uint8_t))) return -ENOMEM; - allocated = MALLOC_SIZEOF_SAFE(rtnl->rbuffer); - iov = IOVEC_MAKE(rtnl->rbuffer, allocated); + allocated = MALLOC_SIZEOF_SAFE(nl->rbuffer); + iov = IOVEC_MAKE(nl->rbuffer, allocated); /* read the pending message */ - r = socket_recv_message(rtnl->fd, &iov, &group, false); + r = socket_recv_message(nl->fd, &iov, &group, false); if (r <= 0) return r; else @@ -313,22 +313,22 @@ int socket_read_message(sd_netlink *rtnl) { /* message did not fit in read buffer */ return -EIO; - if (NLMSG_OK(rtnl->rbuffer, len) && rtnl->rbuffer->nlmsg_flags & NLM_F_MULTI) { + if (NLMSG_OK(nl->rbuffer, len) && nl->rbuffer->nlmsg_flags & NLM_F_MULTI) { multi_part = true; - for (i = 0; i < rtnl->rqueue_partial_size; i++) - if (rtnl_message_get_serial(rtnl->rqueue_partial[i]) == - rtnl->rbuffer->nlmsg_seq) { - first = rtnl->rqueue_partial[i]; + for (i = 0; i < nl->rqueue_partial_size; i++) + if (message_get_serial(nl->rqueue_partial[i]) == + nl->rbuffer->nlmsg_seq) { + first = nl->rqueue_partial[i]; break; } } - for (struct nlmsghdr *new_msg = rtnl->rbuffer; NLMSG_OK(new_msg, len) && !done; new_msg = NLMSG_NEXT(new_msg, len)) { + 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 != rtnl->sockaddr.nl.nl_pid) + if (!group && new_msg->nlmsg_pid != nl->sockaddr.nl.nl_pid) /* not broadcast and not for us */ continue; @@ -346,7 +346,7 @@ int socket_read_message(sd_netlink *rtnl) { } /* check that we support this message type */ - r = type_system_root_get_type(rtnl, &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,12 +356,12 @@ int socket_read_message(sd_netlink *rtnl) { } /* 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; } - r = message_new_empty(rtnl, &m); + r = message_new_empty(nl, &m); if (r < 0) return r; @@ -372,7 +372,7 @@ int socket_read_message(sd_netlink *rtnl) { return -ENOMEM; /* seal and parse the top-level message */ - r = sd_netlink_message_rewind(m, rtnl); + r = sd_netlink_message_rewind(m, nl); if (r < 0) return r; @@ -390,31 +390,31 @@ int socket_read_message(sd_netlink *rtnl) { if (!multi_part || done) { /* we got a complete message, push it on the read queue */ - r = rtnl_rqueue_make_room(rtnl); + r = netlink_rqueue_make_room(nl); if (r < 0) return r; - rtnl->rqueue[rtnl->rqueue_size++] = TAKE_PTR(first); + nl->rqueue[nl->rqueue_size++] = TAKE_PTR(first); - if (multi_part && (i < rtnl->rqueue_partial_size)) { + if (multi_part && (i < nl->rqueue_partial_size)) { /* remove the message form the partial read queue */ - memmove(rtnl->rqueue_partial + i,rtnl->rqueue_partial + i + 1, - sizeof(sd_netlink_message*) * (rtnl->rqueue_partial_size - i - 1)); - rtnl->rqueue_partial_size--; + memmove(nl->rqueue_partial + i, nl->rqueue_partial + i + 1, + sizeof(sd_netlink_message*) * (nl->rqueue_partial_size - i - 1)); + nl->rqueue_partial_size--; } return 1; } else { /* we only got a partial multi-part message, push it on the partial read queue */ - if (i < rtnl->rqueue_partial_size) - rtnl->rqueue_partial[i] = TAKE_PTR(first); + if (i < nl->rqueue_partial_size) + nl->rqueue_partial[i] = TAKE_PTR(first); else { - r = rtnl_rqueue_partial_make_room(rtnl); + r = netlink_rqueue_partial_make_room(nl); if (r < 0) return r; - rtnl->rqueue_partial[rtnl->rqueue_partial_size++] = TAKE_PTR(first); + nl->rqueue_partial[nl->rqueue_partial_size++] = TAKE_PTR(first); } return 0; diff --git a/src/libsystemd/sd-netlink/netlink-types-genl.c b/src/libsystemd/sd-netlink/netlink-types-genl.c new file mode 100644 index 0000000000..0e8783b498 --- /dev/null +++ b/src/libsystemd/sd-netlink/netlink-types-genl.c @@ -0,0 +1,234 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include <netinet/in.h> +#include <sys/socket.h> +#include <linux/batman_adv.h> +#include <linux/fou.h> +#include <linux/genetlink.h> +#include <linux/if.h> +#include <linux/if_macsec.h> +#include <linux/l2tp.h> +#include <linux/nl80211.h> +#include <linux/wireguard.h> + +#include "netlink-genl.h" +#include "netlink-types-internal.h" + +/***************** genl ctrl type systems *****************/ +static const NLType genl_ctrl_mcast_group_types[] = { + [CTRL_ATTR_MCAST_GRP_NAME] = { .type = NETLINK_TYPE_STRING }, + [CTRL_ATTR_MCAST_GRP_ID] = { .type = NETLINK_TYPE_U32 }, +}; + +DEFINE_TYPE_SYSTEM(genl_ctrl_mcast_group); + +static const NLType genl_ctrl_ops_types[] = { + [CTRL_ATTR_OP_ID] = { .type = NETLINK_TYPE_U32 }, + [CTRL_ATTR_OP_FLAGS] = { .type = NETLINK_TYPE_U32 }, +}; + +DEFINE_TYPE_SYSTEM(genl_ctrl_ops); + +static const NLType genl_ctrl_types[] = { + [CTRL_ATTR_FAMILY_ID] = { .type = NETLINK_TYPE_U16 }, + [CTRL_ATTR_FAMILY_NAME] = { .type = NETLINK_TYPE_STRING }, + [CTRL_ATTR_VERSION] = { .type = NETLINK_TYPE_U32 }, + [CTRL_ATTR_HDRSIZE] = { .type = NETLINK_TYPE_U32 }, + [CTRL_ATTR_MAXATTR] = { .type = NETLINK_TYPE_U32 }, + [CTRL_ATTR_OPS] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_ctrl_ops_type_system }, + [CTRL_ATTR_MCAST_GROUPS] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_ctrl_mcast_group_type_system }, + /* + [CTRL_ATTR_POLICY] = { .type = NETLINK_TYPE_NESTED, }, + [CTRL_ATTR_OP_POLICY] = { .type = NETLINK_TYPE_NESTED, } + */ + [CTRL_ATTR_OP] = { .type = NETLINK_TYPE_U32 }, +}; + +/***************** genl batadv type systems *****************/ +static const NLType genl_batadv_types[] = { + [BATADV_ATTR_VERSION] = { .type = NETLINK_TYPE_STRING }, + [BATADV_ATTR_ALGO_NAME] = { .type = NETLINK_TYPE_STRING }, + [BATADV_ATTR_MESH_IFINDEX] = { .type = NETLINK_TYPE_U32 }, + [BATADV_ATTR_MESH_IFNAME] = { .type = NETLINK_TYPE_STRING, .size = IFNAMSIZ }, + [BATADV_ATTR_MESH_ADDRESS] = { .size = ETH_ALEN }, + [BATADV_ATTR_HARD_IFINDEX] = { .type = NETLINK_TYPE_U32 }, + [BATADV_ATTR_HARD_IFNAME] = { .type = NETLINK_TYPE_STRING, .size = IFNAMSIZ }, + [BATADV_ATTR_HARD_ADDRESS] = { .size = ETH_ALEN }, + [BATADV_ATTR_ORIG_ADDRESS] = { .size = ETH_ALEN }, + [BATADV_ATTR_TPMETER_RESULT] = { .type = NETLINK_TYPE_U8 }, + [BATADV_ATTR_TPMETER_TEST_TIME] = { .type = NETLINK_TYPE_U32 }, + [BATADV_ATTR_TPMETER_BYTES] = { .type = NETLINK_TYPE_U64 }, + [BATADV_ATTR_TPMETER_COOKIE] = { .type = NETLINK_TYPE_U32 }, + [BATADV_ATTR_PAD] = { .type = NETLINK_TYPE_UNSPEC }, + [BATADV_ATTR_ACTIVE] = { .type = NETLINK_TYPE_FLAG }, + [BATADV_ATTR_TT_ADDRESS] = { .size = ETH_ALEN }, + [BATADV_ATTR_TT_TTVN] = { .type = NETLINK_TYPE_U8 }, + [BATADV_ATTR_TT_LAST_TTVN] = { .type = NETLINK_TYPE_U8 }, + [BATADV_ATTR_TT_CRC32] = { .type = NETLINK_TYPE_U32 }, + [BATADV_ATTR_TT_VID] = { .type = NETLINK_TYPE_U16 }, + [BATADV_ATTR_TT_FLAGS] = { .type = NETLINK_TYPE_U32 }, + [BATADV_ATTR_FLAG_BEST] = { .type = NETLINK_TYPE_FLAG }, + [BATADV_ATTR_LAST_SEEN_MSECS] = { .type = NETLINK_TYPE_U32 }, + [BATADV_ATTR_NEIGH_ADDRESS] = { .size = ETH_ALEN }, + [BATADV_ATTR_TQ] = { .type = NETLINK_TYPE_U8 }, + [BATADV_ATTR_THROUGHPUT] = { .type = NETLINK_TYPE_U32 }, + [BATADV_ATTR_BANDWIDTH_UP] = { .type = NETLINK_TYPE_U32 }, + [BATADV_ATTR_BANDWIDTH_DOWN] = { .type = NETLINK_TYPE_U32 }, + [BATADV_ATTR_ROUTER] = { .size = ETH_ALEN }, + [BATADV_ATTR_BLA_OWN] = { .type = NETLINK_TYPE_FLAG }, + [BATADV_ATTR_BLA_ADDRESS] = { .size = ETH_ALEN }, + [BATADV_ATTR_BLA_VID] = { .type = NETLINK_TYPE_U16 }, + [BATADV_ATTR_BLA_BACKBONE] = { .size = ETH_ALEN }, + [BATADV_ATTR_BLA_CRC] = { .type = NETLINK_TYPE_U16 }, + [BATADV_ATTR_DAT_CACHE_IP4ADDRESS] = { .type = NETLINK_TYPE_U32 }, + [BATADV_ATTR_DAT_CACHE_HWADDRESS] = { .size = ETH_ALEN }, + [BATADV_ATTR_DAT_CACHE_VID] = { .type = NETLINK_TYPE_U16 }, + [BATADV_ATTR_MCAST_FLAGS] = { .type = NETLINK_TYPE_U32 }, + [BATADV_ATTR_MCAST_FLAGS_PRIV] = { .type = NETLINK_TYPE_U32 }, + [BATADV_ATTR_VLANID] = { .type = NETLINK_TYPE_U16 }, + [BATADV_ATTR_AGGREGATED_OGMS_ENABLED] = { .type = NETLINK_TYPE_U8 }, + [BATADV_ATTR_AP_ISOLATION_ENABLED] = { .type = NETLINK_TYPE_U8 }, + [BATADV_ATTR_ISOLATION_MARK] = { .type = NETLINK_TYPE_U32 }, + [BATADV_ATTR_ISOLATION_MASK] = { .type = NETLINK_TYPE_U32 }, + [BATADV_ATTR_BONDING_ENABLED] = { .type = NETLINK_TYPE_U8 }, + [BATADV_ATTR_BRIDGE_LOOP_AVOIDANCE_ENABLED] = { .type = NETLINK_TYPE_U8 }, + [BATADV_ATTR_DISTRIBUTED_ARP_TABLE_ENABLED] = { .type = NETLINK_TYPE_U8 }, + [BATADV_ATTR_FRAGMENTATION_ENABLED] = { .type = NETLINK_TYPE_U8 }, + [BATADV_ATTR_GW_BANDWIDTH_DOWN] = { .type = NETLINK_TYPE_U32 }, + [BATADV_ATTR_GW_BANDWIDTH_UP] = { .type = NETLINK_TYPE_U32 }, + [BATADV_ATTR_GW_MODE] = { .type = NETLINK_TYPE_U8 }, + [BATADV_ATTR_GW_SEL_CLASS] = { .type = NETLINK_TYPE_U32 }, + [BATADV_ATTR_HOP_PENALTY] = { .type = NETLINK_TYPE_U8 }, + [BATADV_ATTR_LOG_LEVEL] = { .type = NETLINK_TYPE_U32 }, + [BATADV_ATTR_MULTICAST_FORCEFLOOD_ENABLED] = { .type = NETLINK_TYPE_U8 }, + [BATADV_ATTR_MULTICAST_FANOUT] = { .type = NETLINK_TYPE_U32 }, + [BATADV_ATTR_NETWORK_CODING_ENABLED] = { .type = NETLINK_TYPE_U8 }, + [BATADV_ATTR_ORIG_INTERVAL] = { .type = NETLINK_TYPE_U32 }, + [BATADV_ATTR_ELP_INTERVAL] = { .type = NETLINK_TYPE_U32 }, + [BATADV_ATTR_THROUGHPUT_OVERRIDE] = { .type = NETLINK_TYPE_U32 }, +}; + +/***************** genl fou type systems *****************/ +static const NLType genl_fou_types[] = { + [FOU_ATTR_PORT] = { .type = NETLINK_TYPE_U16 }, + [FOU_ATTR_AF] = { .type = NETLINK_TYPE_U8 }, + [FOU_ATTR_IPPROTO] = { .type = NETLINK_TYPE_U8 }, + [FOU_ATTR_TYPE] = { .type = NETLINK_TYPE_U8 }, + [FOU_ATTR_REMCSUM_NOPARTIAL] = { .type = NETLINK_TYPE_FLAG }, + [FOU_ATTR_LOCAL_V4] = { .type = NETLINK_TYPE_IN_ADDR }, + [FOU_ATTR_PEER_V4] = { .type = NETLINK_TYPE_IN_ADDR }, + [FOU_ATTR_LOCAL_V6] = { .type = NETLINK_TYPE_IN_ADDR }, + [FOU_ATTR_PEER_V6] = { .type = NETLINK_TYPE_IN_ADDR}, + [FOU_ATTR_PEER_PORT] = { .type = NETLINK_TYPE_U16}, + [FOU_ATTR_IFINDEX] = { .type = NETLINK_TYPE_U32}, +}; + +/***************** genl l2tp type systems *****************/ +static const NLType genl_l2tp_types[] = { + [L2TP_ATTR_PW_TYPE] = { .type = NETLINK_TYPE_U16 }, + [L2TP_ATTR_ENCAP_TYPE] = { .type = NETLINK_TYPE_U16 }, + [L2TP_ATTR_OFFSET] = { .type = NETLINK_TYPE_U16 }, + [L2TP_ATTR_DATA_SEQ] = { .type = NETLINK_TYPE_U16 }, + [L2TP_ATTR_L2SPEC_TYPE] = { .type = NETLINK_TYPE_U8 }, + [L2TP_ATTR_L2SPEC_LEN] = { .type = NETLINK_TYPE_U8 }, + [L2TP_ATTR_PROTO_VERSION] = { .type = NETLINK_TYPE_U8 }, + [L2TP_ATTR_IFNAME] = { .type = NETLINK_TYPE_STRING }, + [L2TP_ATTR_CONN_ID] = { .type = NETLINK_TYPE_U32 }, + [L2TP_ATTR_PEER_CONN_ID] = { .type = NETLINK_TYPE_U32 }, + [L2TP_ATTR_SESSION_ID] = { .type = NETLINK_TYPE_U32 }, + [L2TP_ATTR_PEER_SESSION_ID] = { .type = NETLINK_TYPE_U32 }, + [L2TP_ATTR_UDP_CSUM] = { .type = NETLINK_TYPE_U8 }, + [L2TP_ATTR_VLAN_ID] = { .type = NETLINK_TYPE_U16 }, + [L2TP_ATTR_RECV_SEQ] = { .type = NETLINK_TYPE_U8 }, + [L2TP_ATTR_SEND_SEQ] = { .type = NETLINK_TYPE_U8 }, + [L2TP_ATTR_LNS_MODE] = { .type = NETLINK_TYPE_U8 }, + [L2TP_ATTR_USING_IPSEC] = { .type = NETLINK_TYPE_U8 }, + [L2TP_ATTR_FD] = { .type = NETLINK_TYPE_U32 }, + [L2TP_ATTR_IP_SADDR] = { .type = NETLINK_TYPE_IN_ADDR }, + [L2TP_ATTR_IP_DADDR] = { .type = NETLINK_TYPE_IN_ADDR }, + [L2TP_ATTR_UDP_SPORT] = { .type = NETLINK_TYPE_U16 }, + [L2TP_ATTR_UDP_DPORT] = { .type = NETLINK_TYPE_U16 }, + [L2TP_ATTR_IP6_SADDR] = { .type = NETLINK_TYPE_IN_ADDR }, + [L2TP_ATTR_IP6_DADDR] = { .type = NETLINK_TYPE_IN_ADDR }, + [L2TP_ATTR_UDP_ZERO_CSUM6_TX] = { .type = NETLINK_TYPE_FLAG }, + [L2TP_ATTR_UDP_ZERO_CSUM6_RX] = { .type = NETLINK_TYPE_FLAG }, +}; + +/***************** genl macsec type systems *****************/ +static const NLType genl_macsec_rxsc_types[] = { + [MACSEC_RXSC_ATTR_SCI] = { .type = NETLINK_TYPE_U64 }, +}; + +DEFINE_TYPE_SYSTEM(genl_macsec_rxsc); + +static const NLType genl_macsec_sa_types[] = { + [MACSEC_SA_ATTR_AN] = { .type = NETLINK_TYPE_U8 }, + [MACSEC_SA_ATTR_ACTIVE] = { .type = NETLINK_TYPE_U8 }, + [MACSEC_SA_ATTR_PN] = { .type = NETLINK_TYPE_U32 }, + [MACSEC_SA_ATTR_KEYID] = { .size = MACSEC_KEYID_LEN }, + [MACSEC_SA_ATTR_KEY] = { .size = MACSEC_MAX_KEY_LEN }, +}; + +DEFINE_TYPE_SYSTEM(genl_macsec_sa); + +static const NLType genl_macsec_types[] = { + [MACSEC_ATTR_IFINDEX] = { .type = NETLINK_TYPE_U32 }, + [MACSEC_ATTR_RXSC_CONFIG] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_macsec_rxsc_type_system }, + [MACSEC_ATTR_SA_CONFIG] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_macsec_sa_type_system }, +}; + +/***************** genl nl80211 type systems *****************/ +static const NLType genl_nl80211_types[] = { + [NL80211_ATTR_IFINDEX] = { .type = NETLINK_TYPE_U32 }, + [NL80211_ATTR_MAC] = { .type = NETLINK_TYPE_ETHER_ADDR }, + [NL80211_ATTR_SSID] = { .type = NETLINK_TYPE_STRING }, + [NL80211_ATTR_IFTYPE] = { .type = NETLINK_TYPE_U32 }, +}; + +/***************** genl wireguard type systems *****************/ +static const NLType genl_wireguard_allowedip_types[] = { + [WGALLOWEDIP_A_FAMILY] = { .type = NETLINK_TYPE_U16 }, + [WGALLOWEDIP_A_IPADDR] = { .type = NETLINK_TYPE_IN_ADDR }, + [WGALLOWEDIP_A_CIDR_MASK] = { .type = NETLINK_TYPE_U8 }, +}; + +DEFINE_TYPE_SYSTEM(genl_wireguard_allowedip); + +static const NLType genl_wireguard_peer_types[] = { + [WGPEER_A_PUBLIC_KEY] = { .size = WG_KEY_LEN }, + [WGPEER_A_FLAGS] = { .type = NETLINK_TYPE_U32 }, + [WGPEER_A_PRESHARED_KEY] = { .size = WG_KEY_LEN }, + [WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL] = { .type = NETLINK_TYPE_U16 }, + [WGPEER_A_ENDPOINT] = { .type = NETLINK_TYPE_SOCKADDR }, + [WGPEER_A_ALLOWEDIPS] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_wireguard_allowedip_type_system }, +}; + +DEFINE_TYPE_SYSTEM(genl_wireguard_peer); + +static const NLType genl_wireguard_types[] = { + [WGDEVICE_A_IFINDEX] = { .type = NETLINK_TYPE_U32 }, + [WGDEVICE_A_IFNAME] = { .type = NETLINK_TYPE_STRING, .size = IFNAMSIZ-1 }, + [WGDEVICE_A_FLAGS] = { .type = NETLINK_TYPE_U32 }, + [WGDEVICE_A_PRIVATE_KEY] = { .size = WG_KEY_LEN }, + [WGDEVICE_A_LISTEN_PORT] = { .type = NETLINK_TYPE_U16 }, + [WGDEVICE_A_FWMARK] = { .type = NETLINK_TYPE_U32 }, + [WGDEVICE_A_PEERS] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_wireguard_peer_type_system }, +}; + +/***************** genl families *****************/ +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), }, +}; + +/* This is the root type system union, so match_attribute is not necessary. */ +DEFINE_TYPE_SYSTEM_UNION_MATCH_SIBLING(genl, 0); + +const NLTypeSystem *genl_get_type_system_by_name(const char *name) { + return type_system_union_get_type_system_by_string(&genl_type_system_union, name); +} diff --git a/src/libsystemd/sd-netlink/netlink-types-internal.h b/src/libsystemd/sd-netlink/netlink-types-internal.h new file mode 100644 index 0000000000..16da6aad0e --- /dev/null +++ b/src/libsystemd/sd-netlink/netlink-types-internal.h @@ -0,0 +1,49 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +#include "macro.h" +#include "netlink-types.h" + +struct NLType { + uint16_t type; + size_t size; + const NLTypeSystem *type_system; + const NLTypeSystemUnion *type_system_union; +}; + +struct NLTypeSystem { + uint16_t count; + const NLType *types; +}; + +typedef struct NLTypeSystemUnionElement { + union { + int protocol; + const char *name; + }; + NLTypeSystem type_system; +} NLTypeSystemUnionElement; + +struct NLTypeSystemUnion { + size_t count; + const NLTypeSystemUnionElement *elements; + NLMatchType match_type; + uint16_t match_attribute; +}; + +#define TYPE_SYSTEM_FROM_TYPE(name) \ + { .count = ELEMENTSOF(name##_types), .types = name##_types } +#define DEFINE_TYPE_SYSTEM(name) \ + static const NLTypeSystem name##_type_system = TYPE_SYSTEM_FROM_TYPE(name) + +#define _DEFINE_TYPE_SYSTEM_UNION(name, type, attr) \ + static const NLTypeSystemUnion name##_type_system_union = { \ + .count = ELEMENTSOF(name##_type_systems), \ + .elements = name##_type_systems, \ + .match_type = type, \ + .match_attribute = attr, \ + } +#define DEFINE_TYPE_SYSTEM_UNION_MATCH_PROTOCOL(name) \ + _DEFINE_TYPE_SYSTEM_UNION(name, NL_MATCH_PROTOCOL, 0) +#define DEFINE_TYPE_SYSTEM_UNION_MATCH_SIBLING(name, attr) \ + _DEFINE_TYPE_SYSTEM_UNION(name, NL_MATCH_SIBLING, attr) diff --git a/src/libsystemd/sd-netlink/netlink-types-nfnl.c b/src/libsystemd/sd-netlink/netlink-types-nfnl.c new file mode 100644 index 0000000000..1ba134a976 --- /dev/null +++ b/src/libsystemd/sd-netlink/netlink-types-nfnl.c @@ -0,0 +1,197 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include <netinet/in.h> +#include <sys/socket.h> +#include <linux/if.h> +#include <linux/netfilter/nf_tables.h> +#include <linux/netfilter/nfnetlink.h> + +#include "netlink-types-internal.h" +#include "string-table.h" + +static const NLType nfnl_nft_table_types[] = { + [NFTA_TABLE_NAME] = { .type = NETLINK_TYPE_STRING, .size = NFT_TABLE_MAXNAMELEN - 1 }, + [NFTA_TABLE_FLAGS] = { .type = NETLINK_TYPE_U32 }, +}; + +DEFINE_TYPE_SYSTEM(nfnl_nft_table); + +static const NLType nfnl_nft_chain_hook_types[] = { + [NFTA_HOOK_HOOKNUM] = { .type = NETLINK_TYPE_U32 }, + [NFTA_HOOK_PRIORITY] = { .type = NETLINK_TYPE_U32 }, + [NFTA_HOOK_DEV] = { .type = NETLINK_TYPE_STRING, .size = IFNAMSIZ - 1 }, +}; + +DEFINE_TYPE_SYSTEM(nfnl_nft_chain_hook); + +static const NLType nfnl_nft_chain_types[] = { + [NFTA_CHAIN_TABLE] = { .type = NETLINK_TYPE_STRING, .size = NFT_TABLE_MAXNAMELEN - 1 }, + [NFTA_CHAIN_NAME] = { .type = NETLINK_TYPE_STRING, .size = NFT_TABLE_MAXNAMELEN - 1 }, + [NFTA_CHAIN_HOOK] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_chain_hook_type_system }, + [NFTA_CHAIN_TYPE] = { .type = NETLINK_TYPE_STRING, .size = 16 }, + [NFTA_CHAIN_FLAGS] = { .type = NETLINK_TYPE_U32 }, +}; + +DEFINE_TYPE_SYSTEM(nfnl_nft_chain); + +static const NLType nfnl_nft_expr_meta_types[] = { + [NFTA_META_DREG] = { .type = NETLINK_TYPE_U32 }, + [NFTA_META_KEY] = { .type = NETLINK_TYPE_U32 }, + [NFTA_META_SREG] = { .type = NETLINK_TYPE_U32 }, +}; + +static const NLType nfnl_nft_expr_payload_types[] = { + [NFTA_PAYLOAD_DREG] = { .type = NETLINK_TYPE_U32 }, + [NFTA_PAYLOAD_BASE] = { .type = NETLINK_TYPE_U32 }, + [NFTA_PAYLOAD_OFFSET] = { .type = NETLINK_TYPE_U32 }, + [NFTA_PAYLOAD_LEN] = { .type = NETLINK_TYPE_U32 }, +}; + +static const NLType nfnl_nft_expr_nat_types[] = { + [NFTA_NAT_TYPE] = { .type = NETLINK_TYPE_U32 }, + [NFTA_NAT_FAMILY] = { .type = NETLINK_TYPE_U32 }, + [NFTA_NAT_REG_ADDR_MIN] = { .type = NETLINK_TYPE_U32 }, + [NFTA_NAT_REG_ADDR_MAX] = { .type = NETLINK_TYPE_U32 }, + [NFTA_NAT_REG_PROTO_MIN] = { .type = NETLINK_TYPE_U32 }, + [NFTA_NAT_REG_PROTO_MAX] = { .type = NETLINK_TYPE_U32 }, + [NFTA_NAT_FLAGS] = { .type = NETLINK_TYPE_U32 }, +}; + +static const NLType nfnl_nft_data_types[] = { + [NFTA_DATA_VALUE] = { .type = NETLINK_TYPE_BINARY }, +}; + +DEFINE_TYPE_SYSTEM(nfnl_nft_data); + +static const NLType nfnl_nft_expr_bitwise_types[] = { + [NFTA_BITWISE_SREG] = { .type = NETLINK_TYPE_U32 }, + [NFTA_BITWISE_DREG] = { .type = NETLINK_TYPE_U32 }, + [NFTA_BITWISE_LEN] = { .type = NETLINK_TYPE_U32 }, + [NFTA_BITWISE_MASK] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_data_type_system }, + [NFTA_BITWISE_XOR] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_data_type_system }, +}; + +static const NLType nfnl_nft_expr_cmp_types[] = { + [NFTA_CMP_SREG] = { .type = NETLINK_TYPE_U32 }, + [NFTA_CMP_OP] = { .type = NETLINK_TYPE_U32 }, + [NFTA_CMP_DATA] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_data_type_system }, +}; + +static const NLType nfnl_nft_expr_fib_types[] = { + [NFTA_FIB_DREG] = { .type = NETLINK_TYPE_U32 }, + [NFTA_FIB_RESULT] = { .type = NETLINK_TYPE_U32 }, + [NFTA_FIB_FLAGS] = { .type = NETLINK_TYPE_U32 }, +}; + +static const NLType nfnl_nft_expr_lookup_types[] = { + [NFTA_LOOKUP_SET] = { .type = NETLINK_TYPE_STRING }, + [NFTA_LOOKUP_SREG] = { .type = NETLINK_TYPE_U32 }, + [NFTA_LOOKUP_DREG] = { .type = NETLINK_TYPE_U32 }, + [NFTA_LOOKUP_FLAGS] = { .type = NETLINK_TYPE_U32 }, +}; + +static const NLType nfnl_nft_expr_masq_types[] = { + [NFTA_MASQ_FLAGS] = { .type = NETLINK_TYPE_U32 }, + [NFTA_MASQ_REG_PROTO_MIN] = { .type = NETLINK_TYPE_U32 }, + [NFTA_MASQ_REG_PROTO_MAX] = { .type = NETLINK_TYPE_U32 }, +}; + +static const NLTypeSystemUnionElement nfnl_expr_data_type_systems[] = { + { .name = "bitwise", .type_system = TYPE_SYSTEM_FROM_TYPE(nfnl_nft_expr_bitwise), }, + { .name = "cmp", .type_system = TYPE_SYSTEM_FROM_TYPE(nfnl_nft_expr_cmp), }, + { .name = "fib", .type_system = TYPE_SYSTEM_FROM_TYPE(nfnl_nft_expr_fib), }, + { .name = "lookup", .type_system = TYPE_SYSTEM_FROM_TYPE(nfnl_nft_expr_lookup), }, + { .name = "masq", .type_system = TYPE_SYSTEM_FROM_TYPE(nfnl_nft_expr_masq), }, + { .name = "meta", .type_system = TYPE_SYSTEM_FROM_TYPE(nfnl_nft_expr_meta), }, + { .name = "nat", .type_system = TYPE_SYSTEM_FROM_TYPE(nfnl_nft_expr_nat), }, + { .name = "payload", .type_system = TYPE_SYSTEM_FROM_TYPE(nfnl_nft_expr_payload), }, +}; + +DEFINE_TYPE_SYSTEM_UNION_MATCH_SIBLING(nfnl_expr_data, NFTA_EXPR_NAME); + +static const NLType nfnl_nft_rule_expr_types[] = { + [NFTA_EXPR_NAME] = { .type = NETLINK_TYPE_STRING, .size = 16 }, + [NFTA_EXPR_DATA] = { .type = NETLINK_TYPE_UNION, .type_system_union = &nfnl_expr_data_type_system_union }, +}; + +DEFINE_TYPE_SYSTEM(nfnl_nft_rule_expr); + +static const NLType nfnl_nft_rule_types[] = { + [NFTA_RULE_TABLE] = { .type = NETLINK_TYPE_STRING, .size = NFT_TABLE_MAXNAMELEN - 1 }, + [NFTA_RULE_CHAIN] = { .type = NETLINK_TYPE_STRING, .size = NFT_TABLE_MAXNAMELEN - 1 }, + [NFTA_RULE_EXPRESSIONS] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_rule_expr_type_system } +}; + +DEFINE_TYPE_SYSTEM(nfnl_nft_rule); + +static const NLType nfnl_nft_set_types[] = { + [NFTA_SET_TABLE] = { .type = NETLINK_TYPE_STRING, .size = NFT_TABLE_MAXNAMELEN - 1 }, + [NFTA_SET_NAME] = { .type = NETLINK_TYPE_STRING, .size = NFT_TABLE_MAXNAMELEN - 1 }, + [NFTA_SET_FLAGS] = { .type = NETLINK_TYPE_U32 }, + [NFTA_SET_KEY_TYPE] = { .type = NETLINK_TYPE_U32 }, + [NFTA_SET_KEY_LEN] = { .type = NETLINK_TYPE_U32 }, + [NFTA_SET_DATA_TYPE] = { .type = NETLINK_TYPE_U32 }, + [NFTA_SET_DATA_LEN] = { .type = NETLINK_TYPE_U32 }, + [NFTA_SET_POLICY] = { .type = NETLINK_TYPE_U32 }, + [NFTA_SET_ID] = { .type = NETLINK_TYPE_U32 }, +}; + +DEFINE_TYPE_SYSTEM(nfnl_nft_set); + +static const NLType nfnl_nft_setelem_types[] = { + [NFTA_SET_ELEM_KEY] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_data_type_system }, + [NFTA_SET_ELEM_DATA] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_data_type_system }, + [NFTA_SET_ELEM_FLAGS] = { .type = NETLINK_TYPE_U32 }, +}; + +DEFINE_TYPE_SYSTEM(nfnl_nft_setelem); + +static const NLType nfnl_nft_setelem_list_types[] = { + [NFTA_SET_ELEM_LIST_TABLE] = { .type = NETLINK_TYPE_STRING, .size = NFT_TABLE_MAXNAMELEN - 1 }, + [NFTA_SET_ELEM_LIST_SET] = { .type = NETLINK_TYPE_STRING, .size = NFT_TABLE_MAXNAMELEN - 1 }, + [NFTA_SET_ELEM_LIST_ELEMENTS] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_setelem_type_system }, +}; + +DEFINE_TYPE_SYSTEM(nfnl_nft_setelem_list); + +static const NLType nfnl_subsys_nft_types [] = { + [NFT_MSG_DELTABLE] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_table_type_system, .size = sizeof(struct nfgenmsg) }, + [NFT_MSG_NEWTABLE] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_table_type_system, .size = sizeof(struct nfgenmsg) }, + [NFT_MSG_NEWCHAIN] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_chain_type_system, .size = sizeof(struct nfgenmsg) }, + [NFT_MSG_NEWRULE] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_rule_type_system, .size = sizeof(struct nfgenmsg) }, + [NFT_MSG_NEWSET] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_set_type_system, .size = sizeof(struct nfgenmsg) }, + [NFT_MSG_NEWSETELEM] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_setelem_list_type_system, .size = sizeof(struct nfgenmsg) }, + [NFT_MSG_DELSETELEM] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_setelem_list_type_system, .size = sizeof(struct nfgenmsg) }, +}; + +DEFINE_TYPE_SYSTEM(nfnl_subsys_nft); + +static const NLType nfnl_msg_batch_types [] = { + [NFNL_BATCH_GENID] = { .type = NETLINK_TYPE_U32 } +}; + +DEFINE_TYPE_SYSTEM(nfnl_msg_batch); + +static const NLType nfnl_subsys_none_types[] = { + [NFNL_MSG_BATCH_BEGIN] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_msg_batch_type_system, .size = sizeof(struct nfgenmsg) }, + [NFNL_MSG_BATCH_END] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_msg_batch_type_system, .size = sizeof(struct nfgenmsg) }, +}; + +DEFINE_TYPE_SYSTEM(nfnl_subsys_none); + +static const NLType nfnl_types[] = { + [NFNL_SUBSYS_NONE] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_subsys_none_type_system }, + [NFNL_SUBSYS_NFTABLES] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_subsys_nft_type_system }, +}; + +DEFINE_TYPE_SYSTEM(nfnl); + +const NLType *nfnl_get_type(uint16_t nlmsg_type) { + const NLTypeSystem *subsys; + + subsys = type_system_get_type_system(&nfnl_type_system, nlmsg_type >> 8); + if (!subsys) + return NULL; + + return type_system_get_type(subsys, nlmsg_type & ((1U << 8) - 1)); +} diff --git a/src/libsystemd/sd-netlink/netlink-types-rtnl.c b/src/libsystemd/sd-netlink/netlink-types-rtnl.c new file mode 100644 index 0000000000..75046e98a9 --- /dev/null +++ b/src/libsystemd/sd-netlink/netlink-types-rtnl.c @@ -0,0 +1,872 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include <netinet/in.h> +#include <sys/socket.h> +#include <linux/batman_adv.h> +#include <linux/can/netlink.h> +#include <linux/can/vxcan.h> +#include <linux/fib_rules.h> +#include <linux/fou.h> +#include <linux/if.h> +#include <linux/if_addr.h> +#include <linux/if_addrlabel.h> +#include <linux/if_bridge.h> +#include <linux/if_link.h> +#include <linux/if_macsec.h> +#include <linux/if_tunnel.h> +#include <linux/ip.h> +#include <linux/l2tp.h> +#include <linux/netlink.h> +#include <linux/nexthop.h> +#include <linux/nl80211.h> +#include <linux/pkt_sched.h> +#include <linux/rtnetlink.h> +#include <linux/veth.h> +#include <linux/wireguard.h> + +#include "sd-netlink.h" + +#include "netlink-types-internal.h" +#include "string-table.h" + +/* Maximum ARP IP target defined in kernel */ +#define BOND_MAX_ARP_TARGETS 16 + +typedef enum { + BOND_ARP_TARGETS_0, + BOND_ARP_TARGETS_1, + BOND_ARP_TARGETS_2, + BOND_ARP_TARGETS_3, + BOND_ARP_TARGETS_4, + BOND_ARP_TARGETS_5, + BOND_ARP_TARGETS_6, + BOND_ARP_TARGETS_7, + BOND_ARP_TARGETS_8, + BOND_ARP_TARGETS_9, + BOND_ARP_TARGETS_10, + BOND_ARP_TARGETS_11, + BOND_ARP_TARGETS_12, + BOND_ARP_TARGETS_13, + BOND_ARP_TARGETS_14, + BOND_ARP_TARGETS_MAX = BOND_MAX_ARP_TARGETS, +} BondArpTargets; + +static const NLTypeSystem rtnl_link_type_system; + +static const NLType rtnl_link_info_data_batadv_types[] = { + [IFLA_BATADV_ALGO_NAME] = { .type = NETLINK_TYPE_STRING, .size = 20 }, +}; + +static const NLType rtnl_link_info_data_veth_types[] = { + [VETH_INFO_PEER] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_link_type_system, .size = sizeof(struct ifinfomsg) }, +}; + +static const NLType rtnl_link_info_data_vxcan_types[] = { + [VXCAN_INFO_PEER] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_link_type_system, .size = sizeof(struct ifinfomsg) }, +}; + +static const NLType rtnl_link_info_data_ipvlan_types[] = { + [IFLA_IPVLAN_MODE] = { .type = NETLINK_TYPE_U16 }, + [IFLA_IPVLAN_FLAGS] = { .type = NETLINK_TYPE_U16 }, +}; + +static const NLType rtnl_macvlan_macaddr_types[] = { + [IFLA_MACVLAN_MACADDR] = { .type = NETLINK_TYPE_ETHER_ADDR }, +}; + +DEFINE_TYPE_SYSTEM(rtnl_macvlan_macaddr); + +static const NLType rtnl_link_info_data_macvlan_types[] = { + [IFLA_MACVLAN_MODE] = { .type = NETLINK_TYPE_U32 }, + [IFLA_MACVLAN_FLAGS] = { .type = NETLINK_TYPE_U16 }, + [IFLA_MACVLAN_MACADDR_MODE] = { .type = NETLINK_TYPE_U32 }, + [IFLA_MACVLAN_MACADDR_DATA] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_macvlan_macaddr_type_system }, + [IFLA_MACVLAN_MACADDR_COUNT] = { .type = NETLINK_TYPE_U32 }, + [IFLA_MACVLAN_BC_QUEUE_LEN] = { .type = NETLINK_TYPE_U32 }, + [IFLA_MACVLAN_BC_QUEUE_LEN_USED] = { .type = NETLINK_TYPE_REJECT }, +}; + +static const NLType rtnl_link_info_data_bridge_types[] = { + [IFLA_BR_FORWARD_DELAY] = { .type = NETLINK_TYPE_U32 }, + [IFLA_BR_HELLO_TIME] = { .type = NETLINK_TYPE_U32 }, + [IFLA_BR_MAX_AGE] = { .type = NETLINK_TYPE_U32 }, + [IFLA_BR_AGEING_TIME] = { .type = NETLINK_TYPE_U32 }, + [IFLA_BR_STP_STATE] = { .type = NETLINK_TYPE_U32 }, + [IFLA_BR_PRIORITY] = { .type = NETLINK_TYPE_U16 }, + [IFLA_BR_VLAN_FILTERING] = { .type = NETLINK_TYPE_U8 }, + [IFLA_BR_VLAN_PROTOCOL] = { .type = NETLINK_TYPE_U16 }, + [IFLA_BR_GROUP_FWD_MASK] = { .type = NETLINK_TYPE_U16 }, + [IFLA_BR_ROOT_PORT] = { .type = NETLINK_TYPE_U16 }, + [IFLA_BR_ROOT_PATH_COST] = { .type = NETLINK_TYPE_U32 }, + [IFLA_BR_TOPOLOGY_CHANGE] = { .type = NETLINK_TYPE_U8 }, + [IFLA_BR_TOPOLOGY_CHANGE_DETECTED] = { .type = NETLINK_TYPE_U8 }, + [IFLA_BR_HELLO_TIMER] = { .type = NETLINK_TYPE_U16 }, + [IFLA_BR_TCN_TIMER] = { .type = NETLINK_TYPE_U16 }, + [IFLA_BR_TOPOLOGY_CHANGE_TIMER] = { .type = NETLINK_TYPE_U16 }, + [IFLA_BR_GC_TIMER] = { .type = NETLINK_TYPE_U64 }, + [IFLA_BR_GROUP_ADDR] = { .type = NETLINK_TYPE_U16 }, + [IFLA_BR_FDB_FLUSH] = { .type = NETLINK_TYPE_U16 }, + [IFLA_BR_MCAST_ROUTER] = { .type = NETLINK_TYPE_U8 }, + [IFLA_BR_MCAST_SNOOPING] = { .type = NETLINK_TYPE_U8 }, + [IFLA_BR_MCAST_QUERY_USE_IFADDR] = { .type = NETLINK_TYPE_U8 }, + [IFLA_BR_MCAST_QUERIER] = { .type = NETLINK_TYPE_U8 }, + [IFLA_BR_MCAST_HASH_ELASTICITY] = { .type = NETLINK_TYPE_U32 }, + [IFLA_BR_MCAST_HASH_MAX] = { .type = NETLINK_TYPE_U16 }, + [IFLA_BR_MCAST_LAST_MEMBER_CNT] = { .type = NETLINK_TYPE_U32 }, + [IFLA_BR_MCAST_STARTUP_QUERY_CNT] = { .type = NETLINK_TYPE_U16 }, + [IFLA_BR_MCAST_LAST_MEMBER_INTVL] = { .type = NETLINK_TYPE_U64 }, + [IFLA_BR_MCAST_MEMBERSHIP_INTVL] = { .type = NETLINK_TYPE_U64 }, + [IFLA_BR_MCAST_QUERIER_INTVL] = { .type = NETLINK_TYPE_U64 }, + [IFLA_BR_MCAST_QUERY_INTVL] = { .type = NETLINK_TYPE_U64 }, + [IFLA_BR_MCAST_QUERY_RESPONSE_INTVL] = { .type = NETLINK_TYPE_U64 }, + [IFLA_BR_MCAST_STARTUP_QUERY_INTVL] = { .type = NETLINK_TYPE_U64 }, + [IFLA_BR_NF_CALL_IPTABLES] = { .type = NETLINK_TYPE_U8 }, + [IFLA_BR_NF_CALL_IP6TABLES] = { .type = NETLINK_TYPE_U8 }, + [IFLA_BR_NF_CALL_ARPTABLES] = { .type = NETLINK_TYPE_U8 }, + [IFLA_BR_VLAN_DEFAULT_PVID] = { .type = NETLINK_TYPE_U16 }, + [IFLA_BR_MCAST_IGMP_VERSION] = { .type = NETLINK_TYPE_U8 }, +}; + +static const NLType rtnl_vlan_qos_map_types[] = { + [IFLA_VLAN_QOS_MAPPING] = { .size = sizeof(struct ifla_vlan_qos_mapping) }, +}; + +DEFINE_TYPE_SYSTEM(rtnl_vlan_qos_map); + +static const NLType rtnl_link_info_data_vlan_types[] = { + [IFLA_VLAN_ID] = { .type = NETLINK_TYPE_U16 }, + [IFLA_VLAN_FLAGS] = { .size = sizeof(struct ifla_vlan_flags) }, + [IFLA_VLAN_EGRESS_QOS] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_vlan_qos_map_type_system }, + [IFLA_VLAN_INGRESS_QOS] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_vlan_qos_map_type_system }, + [IFLA_VLAN_PROTOCOL] = { .type = NETLINK_TYPE_U16 }, +}; + +static const NLType rtnl_link_info_data_vxlan_types[] = { + [IFLA_VXLAN_ID] = { .type = NETLINK_TYPE_U32 }, + [IFLA_VXLAN_GROUP] = { .type = NETLINK_TYPE_IN_ADDR }, + [IFLA_VXLAN_LINK] = { .type = NETLINK_TYPE_U32 }, + [IFLA_VXLAN_LOCAL] = { .type = NETLINK_TYPE_IN_ADDR }, + [IFLA_VXLAN_TTL] = { .type = NETLINK_TYPE_U8 }, + [IFLA_VXLAN_TOS] = { .type = NETLINK_TYPE_U8 }, + [IFLA_VXLAN_LEARNING] = { .type = NETLINK_TYPE_U8 }, + [IFLA_VXLAN_AGEING] = { .type = NETLINK_TYPE_U32 }, + [IFLA_VXLAN_LIMIT] = { .type = NETLINK_TYPE_U32 }, + [IFLA_VXLAN_PORT_RANGE] = { .type = NETLINK_TYPE_U32}, + [IFLA_VXLAN_PROXY] = { .type = NETLINK_TYPE_U8 }, + [IFLA_VXLAN_RSC] = { .type = NETLINK_TYPE_U8 }, + [IFLA_VXLAN_L2MISS] = { .type = NETLINK_TYPE_U8 }, + [IFLA_VXLAN_L3MISS] = { .type = NETLINK_TYPE_U8 }, + [IFLA_VXLAN_PORT] = { .type = NETLINK_TYPE_U16 }, + [IFLA_VXLAN_GROUP6] = { .type = NETLINK_TYPE_IN_ADDR }, + [IFLA_VXLAN_LOCAL6] = { .type = NETLINK_TYPE_IN_ADDR }, + [IFLA_VXLAN_UDP_CSUM] = { .type = NETLINK_TYPE_U8 }, + [IFLA_VXLAN_UDP_ZERO_CSUM6_TX] = { .type = NETLINK_TYPE_U8 }, + [IFLA_VXLAN_UDP_ZERO_CSUM6_RX] = { .type = NETLINK_TYPE_U8 }, + [IFLA_VXLAN_REMCSUM_TX] = { .type = NETLINK_TYPE_U8 }, + [IFLA_VXLAN_REMCSUM_RX] = { .type = NETLINK_TYPE_U8 }, + [IFLA_VXLAN_GBP] = { .type = NETLINK_TYPE_FLAG }, + [IFLA_VXLAN_REMCSUM_NOPARTIAL] = { .type = NETLINK_TYPE_FLAG }, + [IFLA_VXLAN_COLLECT_METADATA] = { .type = NETLINK_TYPE_U8 }, + [IFLA_VXLAN_LABEL] = { .type = NETLINK_TYPE_U32 }, + [IFLA_VXLAN_GPE] = { .type = NETLINK_TYPE_FLAG }, + [IFLA_VXLAN_TTL_INHERIT] = { .type = NETLINK_TYPE_FLAG }, + [IFLA_VXLAN_DF] = { .type = NETLINK_TYPE_U8 }, +}; + +static const NLType rtnl_bond_arp_target_types[] = { + [BOND_ARP_TARGETS_0] = { .type = NETLINK_TYPE_U32 }, + [BOND_ARP_TARGETS_1] = { .type = NETLINK_TYPE_U32 }, + [BOND_ARP_TARGETS_2] = { .type = NETLINK_TYPE_U32 }, + [BOND_ARP_TARGETS_3] = { .type = NETLINK_TYPE_U32 }, + [BOND_ARP_TARGETS_4] = { .type = NETLINK_TYPE_U32 }, + [BOND_ARP_TARGETS_5] = { .type = NETLINK_TYPE_U32 }, + [BOND_ARP_TARGETS_6] = { .type = NETLINK_TYPE_U32 }, + [BOND_ARP_TARGETS_7] = { .type = NETLINK_TYPE_U32 }, + [BOND_ARP_TARGETS_8] = { .type = NETLINK_TYPE_U32 }, + [BOND_ARP_TARGETS_9] = { .type = NETLINK_TYPE_U32 }, + [BOND_ARP_TARGETS_10] = { .type = NETLINK_TYPE_U32 }, + [BOND_ARP_TARGETS_11] = { .type = NETLINK_TYPE_U32 }, + [BOND_ARP_TARGETS_12] = { .type = NETLINK_TYPE_U32 }, + [BOND_ARP_TARGETS_13] = { .type = NETLINK_TYPE_U32 }, + [BOND_ARP_TARGETS_14] = { .type = NETLINK_TYPE_U32 }, + [BOND_ARP_TARGETS_MAX] = { .type = NETLINK_TYPE_U32 }, +}; + +DEFINE_TYPE_SYSTEM(rtnl_bond_arp_target); + +static const NLType rtnl_link_info_data_bond_types[] = { + [IFLA_BOND_MODE] = { .type = NETLINK_TYPE_U8 }, + [IFLA_BOND_ACTIVE_SLAVE] = { .type = NETLINK_TYPE_U32 }, + [IFLA_BOND_MIIMON] = { .type = NETLINK_TYPE_U32 }, + [IFLA_BOND_UPDELAY] = { .type = NETLINK_TYPE_U32 }, + [IFLA_BOND_DOWNDELAY] = { .type = NETLINK_TYPE_U32 }, + [IFLA_BOND_USE_CARRIER] = { .type = NETLINK_TYPE_U8 }, + [IFLA_BOND_ARP_INTERVAL] = { .type = NETLINK_TYPE_U32 }, + [IFLA_BOND_ARP_IP_TARGET] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_bond_arp_target_type_system }, + [IFLA_BOND_ARP_VALIDATE] = { .type = NETLINK_TYPE_U32 }, + [IFLA_BOND_ARP_ALL_TARGETS] = { .type = NETLINK_TYPE_U32 }, + [IFLA_BOND_PRIMARY] = { .type = NETLINK_TYPE_U32 }, + [IFLA_BOND_PRIMARY_RESELECT] = { .type = NETLINK_TYPE_U8 }, + [IFLA_BOND_FAIL_OVER_MAC] = { .type = NETLINK_TYPE_U8 }, + [IFLA_BOND_XMIT_HASH_POLICY] = { .type = NETLINK_TYPE_U8 }, + [IFLA_BOND_RESEND_IGMP] = { .type = NETLINK_TYPE_U32 }, + [IFLA_BOND_NUM_PEER_NOTIF] = { .type = NETLINK_TYPE_U8 }, + [IFLA_BOND_ALL_SLAVES_ACTIVE] = { .type = NETLINK_TYPE_U8 }, + [IFLA_BOND_MIN_LINKS] = { .type = NETLINK_TYPE_U32 }, + [IFLA_BOND_LP_INTERVAL] = { .type = NETLINK_TYPE_U32 }, + [IFLA_BOND_PACKETS_PER_SLAVE] = { .type = NETLINK_TYPE_U32 }, + [IFLA_BOND_AD_LACP_RATE] = { .type = NETLINK_TYPE_U8 }, + [IFLA_BOND_AD_SELECT] = { .type = NETLINK_TYPE_U8 }, + [IFLA_BOND_AD_INFO] = { .type = NETLINK_TYPE_NESTED }, + [IFLA_BOND_AD_ACTOR_SYS_PRIO] = { .type = NETLINK_TYPE_U16 }, + [IFLA_BOND_AD_USER_PORT_KEY] = { .type = NETLINK_TYPE_U16 }, + [IFLA_BOND_AD_ACTOR_SYSTEM] = { .type = NETLINK_TYPE_ETHER_ADDR }, + [IFLA_BOND_TLB_DYNAMIC_LB] = { .type = NETLINK_TYPE_U8 }, +}; + +static const NLType rtnl_link_info_data_iptun_types[] = { + [IFLA_IPTUN_LINK] = { .type = NETLINK_TYPE_U32 }, + [IFLA_IPTUN_LOCAL] = { .type = NETLINK_TYPE_IN_ADDR }, + [IFLA_IPTUN_REMOTE] = { .type = NETLINK_TYPE_IN_ADDR }, + [IFLA_IPTUN_TTL] = { .type = NETLINK_TYPE_U8 }, + [IFLA_IPTUN_TOS] = { .type = NETLINK_TYPE_U8 }, + [IFLA_IPTUN_PMTUDISC] = { .type = NETLINK_TYPE_U8 }, + [IFLA_IPTUN_FLAGS] = { .type = NETLINK_TYPE_U16 }, + [IFLA_IPTUN_PROTO] = { .type = NETLINK_TYPE_U8 }, + [IFLA_IPTUN_6RD_PREFIX] = { .type = NETLINK_TYPE_IN_ADDR }, + [IFLA_IPTUN_6RD_RELAY_PREFIX] = { .type = NETLINK_TYPE_U32 }, + [IFLA_IPTUN_6RD_PREFIXLEN] = { .type = NETLINK_TYPE_U16 }, + [IFLA_IPTUN_6RD_RELAY_PREFIXLEN] = { .type = NETLINK_TYPE_U16 }, + [IFLA_IPTUN_ENCAP_TYPE] = { .type = NETLINK_TYPE_U16 }, + [IFLA_IPTUN_ENCAP_FLAGS] = { .type = NETLINK_TYPE_U16 }, + [IFLA_IPTUN_ENCAP_SPORT] = { .type = NETLINK_TYPE_U16 }, + [IFLA_IPTUN_ENCAP_DPORT] = { .type = NETLINK_TYPE_U16 }, +}; + +static const NLType rtnl_link_info_data_ipgre_types[] = { + [IFLA_GRE_LINK] = { .type = NETLINK_TYPE_U32 }, + [IFLA_GRE_IFLAGS] = { .type = NETLINK_TYPE_U16 }, + [IFLA_GRE_OFLAGS] = { .type = NETLINK_TYPE_U16 }, + [IFLA_GRE_IKEY] = { .type = NETLINK_TYPE_U32 }, + [IFLA_GRE_OKEY] = { .type = NETLINK_TYPE_U32 }, + [IFLA_GRE_LOCAL] = { .type = NETLINK_TYPE_IN_ADDR }, + [IFLA_GRE_REMOTE] = { .type = NETLINK_TYPE_IN_ADDR }, + [IFLA_GRE_TTL] = { .type = NETLINK_TYPE_U8 }, + [IFLA_GRE_TOS] = { .type = NETLINK_TYPE_U8 }, + [IFLA_GRE_PMTUDISC] = { .type = NETLINK_TYPE_U8 }, + [IFLA_GRE_FLOWINFO] = { .type = NETLINK_TYPE_U32 }, + [IFLA_GRE_FLAGS] = { .type = NETLINK_TYPE_U32 }, + [IFLA_GRE_ENCAP_TYPE] = { .type = NETLINK_TYPE_U16 }, + [IFLA_GRE_ENCAP_FLAGS] = { .type = NETLINK_TYPE_U16 }, + [IFLA_GRE_ENCAP_SPORT] = { .type = NETLINK_TYPE_U16 }, + [IFLA_GRE_ENCAP_DPORT] = { .type = NETLINK_TYPE_U16 }, + [IFLA_GRE_ERSPAN_INDEX] = { .type = NETLINK_TYPE_U32 }, +}; + +static const NLType rtnl_link_info_data_ipvti_types[] = { + [IFLA_VTI_LINK] = { .type = NETLINK_TYPE_U32 }, + [IFLA_VTI_IKEY] = { .type = NETLINK_TYPE_U32 }, + [IFLA_VTI_OKEY] = { .type = NETLINK_TYPE_U32 }, + [IFLA_VTI_LOCAL] = { .type = NETLINK_TYPE_IN_ADDR }, + [IFLA_VTI_REMOTE] = { .type = NETLINK_TYPE_IN_ADDR }, +}; + +static const NLType rtnl_link_info_data_ip6tnl_types[] = { + [IFLA_IPTUN_LINK] = { .type = NETLINK_TYPE_U32 }, + [IFLA_IPTUN_LOCAL] = { .type = NETLINK_TYPE_IN_ADDR }, + [IFLA_IPTUN_REMOTE] = { .type = NETLINK_TYPE_IN_ADDR }, + [IFLA_IPTUN_TTL] = { .type = NETLINK_TYPE_U8 }, + [IFLA_IPTUN_FLAGS] = { .type = NETLINK_TYPE_U32 }, + [IFLA_IPTUN_PROTO] = { .type = NETLINK_TYPE_U8 }, + [IFLA_IPTUN_ENCAP_LIMIT] = { .type = NETLINK_TYPE_U8 }, + [IFLA_IPTUN_FLOWINFO] = { .type = NETLINK_TYPE_U32 }, +}; + +static const NLType rtnl_link_info_data_vrf_types[] = { + [IFLA_VRF_TABLE] = { .type = NETLINK_TYPE_U32 }, +}; + +static const NLType rtnl_link_info_data_geneve_types[] = { + [IFLA_GENEVE_ID] = { .type = NETLINK_TYPE_U32 }, + [IFLA_GENEVE_TTL] = { .type = NETLINK_TYPE_U8 }, + [IFLA_GENEVE_TOS] = { .type = NETLINK_TYPE_U8 }, + [IFLA_GENEVE_PORT] = { .type = NETLINK_TYPE_U16 }, + [IFLA_GENEVE_REMOTE] = { .type = NETLINK_TYPE_IN_ADDR }, + [IFLA_GENEVE_REMOTE6] = { .type = NETLINK_TYPE_IN_ADDR }, + [IFLA_GENEVE_UDP_CSUM] = { .type = NETLINK_TYPE_U8 }, + [IFLA_GENEVE_UDP_ZERO_CSUM6_TX] = { .type = NETLINK_TYPE_U8 }, + [IFLA_GENEVE_UDP_ZERO_CSUM6_RX] = { .type = NETLINK_TYPE_U8 }, + [IFLA_GENEVE_LABEL] = { .type = NETLINK_TYPE_U32 }, + [IFLA_GENEVE_TTL_INHERIT] = { .type = NETLINK_TYPE_U8 }, + [IFLA_GENEVE_DF] = { .type = NETLINK_TYPE_U8 }, +}; + +static const NLType rtnl_link_info_data_can_types[] = { + [IFLA_CAN_BITTIMING] = { .size = sizeof(struct can_bittiming) }, + [IFLA_CAN_RESTART_MS] = { .type = NETLINK_TYPE_U32 }, + [IFLA_CAN_CTRLMODE] = { .size = sizeof(struct can_ctrlmode) }, + [IFLA_CAN_TERMINATION] = { .type = NETLINK_TYPE_U16 }, +}; + +static const NLType rtnl_link_info_data_macsec_types[] = { + [IFLA_MACSEC_SCI] = { .type = NETLINK_TYPE_U64 }, + [IFLA_MACSEC_PORT] = { .type = NETLINK_TYPE_U16 }, + [IFLA_MACSEC_ICV_LEN] = { .type = NETLINK_TYPE_U8 }, + [IFLA_MACSEC_CIPHER_SUITE] = { .type = NETLINK_TYPE_U64 }, + [IFLA_MACSEC_WINDOW] = { .type = NETLINK_TYPE_U32 }, + [IFLA_MACSEC_ENCODING_SA] = { .type = NETLINK_TYPE_U8 }, + [IFLA_MACSEC_ENCRYPT] = { .type = NETLINK_TYPE_U8 }, + [IFLA_MACSEC_PROTECT] = { .type = NETLINK_TYPE_U8 }, + [IFLA_MACSEC_INC_SCI] = { .type = NETLINK_TYPE_U8 }, + [IFLA_MACSEC_ES] = { .type = NETLINK_TYPE_U8 }, + [IFLA_MACSEC_SCB] = { .type = NETLINK_TYPE_U8 }, + [IFLA_MACSEC_REPLAY_PROTECT] = { .type = NETLINK_TYPE_U8 }, + [IFLA_MACSEC_VALIDATION] = { .type = NETLINK_TYPE_U8 }, +}; + +static const NLType rtnl_link_info_data_xfrm_types[] = { + [IFLA_XFRM_LINK] = { .type = NETLINK_TYPE_U32 }, + [IFLA_XFRM_IF_ID] = { .type = NETLINK_TYPE_U32 } +}; + +static const NLType rtnl_link_info_data_bareudp_types[] = { + [IFLA_BAREUDP_PORT] = { .type = NETLINK_TYPE_U16 }, + [IFLA_BAREUDP_ETHERTYPE] = { .type = NETLINK_TYPE_U16 }, + [IFLA_BAREUDP_SRCPORT_MIN] = { .type = NETLINK_TYPE_U16 }, + [IFLA_BAREUDP_MULTIPROTO_MODE] = { .type = NETLINK_TYPE_FLAG }, +}; + +static const NLTypeSystemUnionElement rtnl_link_info_data_type_systems[] = { + { .name = "bareudp", .type_system = TYPE_SYSTEM_FROM_TYPE(rtnl_link_info_data_bareudp), }, + { .name = "batadv", .type_system = TYPE_SYSTEM_FROM_TYPE(rtnl_link_info_data_batadv), }, + { .name = "bond", .type_system = TYPE_SYSTEM_FROM_TYPE(rtnl_link_info_data_bond), }, + { .name = "bridge", .type_system = TYPE_SYSTEM_FROM_TYPE(rtnl_link_info_data_bridge), }, + { .name = "can", .type_system = TYPE_SYSTEM_FROM_TYPE(rtnl_link_info_data_can), }, + { .name = "dummy", }, + { .name = "erspan", .type_system = TYPE_SYSTEM_FROM_TYPE(rtnl_link_info_data_ipgre), }, + { .name = "geneve", .type_system = TYPE_SYSTEM_FROM_TYPE(rtnl_link_info_data_geneve), }, + { .name = "gre", .type_system = TYPE_SYSTEM_FROM_TYPE(rtnl_link_info_data_ipgre), }, + { .name = "gretap", .type_system = TYPE_SYSTEM_FROM_TYPE(rtnl_link_info_data_ipgre), }, + { .name = "ifb", }, + { .name = "ip6gre", .type_system = TYPE_SYSTEM_FROM_TYPE(rtnl_link_info_data_ipgre), }, + { .name = "ip6gretap", .type_system = TYPE_SYSTEM_FROM_TYPE(rtnl_link_info_data_ipgre), }, + { .name = "ip6tnl", .type_system = TYPE_SYSTEM_FROM_TYPE(rtnl_link_info_data_ip6tnl), }, + { .name = "ipip", .type_system = TYPE_SYSTEM_FROM_TYPE(rtnl_link_info_data_iptun), }, + { .name = "ipvlan", .type_system = TYPE_SYSTEM_FROM_TYPE(rtnl_link_info_data_ipvlan), }, + { .name = "ipvtap", .type_system = TYPE_SYSTEM_FROM_TYPE(rtnl_link_info_data_ipvlan), }, + { .name = "macsec", .type_system = TYPE_SYSTEM_FROM_TYPE(rtnl_link_info_data_macsec), }, + { .name = "macvlan", .type_system = TYPE_SYSTEM_FROM_TYPE(rtnl_link_info_data_macvlan), }, + { .name = "macvtap", .type_system = TYPE_SYSTEM_FROM_TYPE(rtnl_link_info_data_macvlan), }, + { .name = "netdevsim", }, + { .name = "nlmon", }, + { .name = "sit", .type_system = TYPE_SYSTEM_FROM_TYPE(rtnl_link_info_data_iptun), }, + { .name = "vcan", }, + { .name = "veth", .type_system = TYPE_SYSTEM_FROM_TYPE(rtnl_link_info_data_veth), }, + { .name = "vlan", .type_system = TYPE_SYSTEM_FROM_TYPE(rtnl_link_info_data_vlan), }, + { .name = "vrf", .type_system = TYPE_SYSTEM_FROM_TYPE(rtnl_link_info_data_vrf), }, + { .name = "vti", .type_system = TYPE_SYSTEM_FROM_TYPE(rtnl_link_info_data_ipvti), }, + { .name = "vti6", .type_system = TYPE_SYSTEM_FROM_TYPE(rtnl_link_info_data_ipvti), }, + { .name = "vxcan", .type_system = TYPE_SYSTEM_FROM_TYPE(rtnl_link_info_data_vxcan), }, + { .name = "vxlan", .type_system = TYPE_SYSTEM_FROM_TYPE(rtnl_link_info_data_vxlan), }, + { .name = "wireguard", }, + { .name = "xfrm", .type_system = TYPE_SYSTEM_FROM_TYPE(rtnl_link_info_data_xfrm), }, +}; + +DEFINE_TYPE_SYSTEM_UNION_MATCH_SIBLING(rtnl_link_info_data, IFLA_INFO_KIND); + +static const NLType rtnl_link_info_types[] = { + [IFLA_INFO_KIND] = { .type = NETLINK_TYPE_STRING }, + [IFLA_INFO_DATA] = { .type = NETLINK_TYPE_UNION, .type_system_union = &rtnl_link_info_data_type_system_union }, +/* + [IFLA_INFO_XSTATS], + [IFLA_INFO_SLAVE_KIND] = { .type = NETLINK_TYPE_STRING }, + [IFLA_INFO_SLAVE_DATA] = { .type = NETLINK_TYPE_NESTED }, +*/ +}; + +DEFINE_TYPE_SYSTEM(rtnl_link_info); + +static const struct NLType rtnl_prot_info_bridge_port_types[] = { + [IFLA_BRPORT_STATE] = { .type = NETLINK_TYPE_U8 }, + [IFLA_BRPORT_COST] = { .type = NETLINK_TYPE_U32 }, + [IFLA_BRPORT_PRIORITY] = { .type = NETLINK_TYPE_U16 }, + [IFLA_BRPORT_MODE] = { .type = NETLINK_TYPE_U8 }, + [IFLA_BRPORT_GUARD] = { .type = NETLINK_TYPE_U8 }, + [IFLA_BRPORT_PROTECT] = { .type = NETLINK_TYPE_U8 }, + [IFLA_BRPORT_FAST_LEAVE] = { .type = NETLINK_TYPE_U8 }, + [IFLA_BRPORT_LEARNING] = { .type = NETLINK_TYPE_U8 }, + [IFLA_BRPORT_UNICAST_FLOOD] = { .type = NETLINK_TYPE_U8 }, + [IFLA_BRPORT_PROXYARP] = { .type = NETLINK_TYPE_U8 }, + [IFLA_BRPORT_LEARNING_SYNC] = { .type = NETLINK_TYPE_U8 }, + [IFLA_BRPORT_PROXYARP_WIFI] = { .type = NETLINK_TYPE_U8 }, + [IFLA_BRPORT_ROOT_ID] = { .type = NETLINK_TYPE_U8 }, + [IFLA_BRPORT_BRIDGE_ID] = { .type = NETLINK_TYPE_U8 }, + [IFLA_BRPORT_DESIGNATED_PORT] = { .type = NETLINK_TYPE_U16 }, + [IFLA_BRPORT_DESIGNATED_COST] = { .type = NETLINK_TYPE_U16 }, + [IFLA_BRPORT_ID] = { .type = NETLINK_TYPE_U16 }, + [IFLA_BRPORT_NO] = { .type = NETLINK_TYPE_U16 }, + [IFLA_BRPORT_TOPOLOGY_CHANGE_ACK] = { .type = NETLINK_TYPE_U8 }, + [IFLA_BRPORT_CONFIG_PENDING] = { .type = NETLINK_TYPE_U8 }, + [IFLA_BRPORT_MESSAGE_AGE_TIMER] = { .type = NETLINK_TYPE_U64 }, + [IFLA_BRPORT_FORWARD_DELAY_TIMER] = { .type = NETLINK_TYPE_U64 }, + [IFLA_BRPORT_HOLD_TIMER] = { .type = NETLINK_TYPE_U64 }, + [IFLA_BRPORT_FLUSH] = { .type = NETLINK_TYPE_U8 }, + [IFLA_BRPORT_MULTICAST_ROUTER] = { .type = NETLINK_TYPE_U8 }, + [IFLA_BRPORT_PAD] = { .type = NETLINK_TYPE_U8 }, + [IFLA_BRPORT_MCAST_FLOOD] = { .type = NETLINK_TYPE_U8 }, + [IFLA_BRPORT_MCAST_TO_UCAST] = { .type = NETLINK_TYPE_U8 }, + [IFLA_BRPORT_VLAN_TUNNEL] = { .type = NETLINK_TYPE_U8 }, + [IFLA_BRPORT_BCAST_FLOOD] = { .type = NETLINK_TYPE_U8 }, + [IFLA_BRPORT_GROUP_FWD_MASK] = { .type = NETLINK_TYPE_U16 }, + [IFLA_BRPORT_NEIGH_SUPPRESS] = { .type = NETLINK_TYPE_U8 }, + [IFLA_BRPORT_ISOLATED] = { .type = NETLINK_TYPE_U8 }, + [IFLA_BRPORT_BACKUP_PORT] = { .type = NETLINK_TYPE_U32 }, +}; + +static const NLTypeSystemUnionElement rtnl_prot_info_type_systems[] = { + { .protocol = AF_BRIDGE, .type_system = TYPE_SYSTEM_FROM_TYPE(rtnl_prot_info_bridge_port), }, +}; + +DEFINE_TYPE_SYSTEM_UNION_MATCH_PROTOCOL(rtnl_prot_info); + +static const struct NLType rtnl_af_spec_inet6_types[] = { + [IFLA_INET6_FLAGS] = { .type = NETLINK_TYPE_U32 }, +/* + IFLA_INET6_CONF, + IFLA_INET6_STATS, + IFLA_INET6_MCAST, + IFLA_INET6_CACHEINFO, + IFLA_INET6_ICMP6STATS, +*/ + [IFLA_INET6_TOKEN] = { .type = NETLINK_TYPE_IN_ADDR }, + [IFLA_INET6_ADDR_GEN_MODE] = { .type = NETLINK_TYPE_U8 }, +}; + +DEFINE_TYPE_SYSTEM(rtnl_af_spec_inet6); + +static const NLType rtnl_af_spec_unspec_types[] = { + [AF_INET6] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_af_spec_inet6_type_system }, +}; + +static const NLType rtnl_af_spec_bridge_types[] = { + [IFLA_BRIDGE_FLAGS] = { .type = NETLINK_TYPE_U16 }, + [IFLA_BRIDGE_VLAN_INFO] = { .size = sizeof(struct bridge_vlan_info) }, +}; + +static const NLTypeSystemUnionElement rtnl_af_spec_type_systems[] = { + { .protocol = AF_UNSPEC, .type_system = TYPE_SYSTEM_FROM_TYPE(rtnl_af_spec_unspec), }, + { .protocol = AF_BRIDGE, .type_system = TYPE_SYSTEM_FROM_TYPE(rtnl_af_spec_bridge), }, +}; + +DEFINE_TYPE_SYSTEM_UNION_MATCH_PROTOCOL(rtnl_af_spec); + +static const NLType rtnl_prop_list_types[] = { + [IFLA_ALT_IFNAME] = { .type = NETLINK_TYPE_STRING, .size = ALTIFNAMSIZ - 1 }, +}; + +DEFINE_TYPE_SYSTEM(rtnl_prop_list); + +static const NLType rtnl_vf_vlan_list_types[] = { + [IFLA_VF_VLAN_INFO] = { .size = sizeof(struct ifla_vf_vlan_info) }, +}; + +DEFINE_TYPE_SYSTEM(rtnl_vf_vlan_list); + +static const NLType rtnl_vf_info_types[] = { + [IFLA_VF_MAC] = { .size = sizeof(struct ifla_vf_mac) }, + [IFLA_VF_VLAN] = { .size = sizeof(struct ifla_vf_vlan) }, + [IFLA_VF_VLAN_LIST] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_vf_vlan_list_type_system}, + [IFLA_VF_TX_RATE] = { .size = sizeof(struct ifla_vf_tx_rate) }, + [IFLA_VF_SPOOFCHK] = { .size = sizeof(struct ifla_vf_spoofchk) }, + [IFLA_VF_RATE] = { .size = sizeof(struct ifla_vf_rate) }, + [IFLA_VF_LINK_STATE] = { .size = sizeof(struct ifla_vf_link_state) }, + [IFLA_VF_RSS_QUERY_EN] = { .size = sizeof(struct ifla_vf_rss_query_en) }, + [IFLA_VF_TRUST] = { .size = sizeof(struct ifla_vf_trust) }, + [IFLA_VF_IB_NODE_GUID] = { .size = sizeof(struct ifla_vf_guid) }, + [IFLA_VF_IB_PORT_GUID] = { .size = sizeof(struct ifla_vf_guid) }, +}; + +DEFINE_TYPE_SYSTEM(rtnl_vf_info); + +static const NLType rtnl_vfinfo_list_types[] = { + [IFLA_VF_INFO] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_vf_info_type_system }, +}; + +DEFINE_TYPE_SYSTEM(rtnl_vfinfo_list); + +static const NLType rtnl_link_types[] = { + [IFLA_ADDRESS] = { .type = NETLINK_TYPE_ETHER_ADDR }, + [IFLA_BROADCAST] = { .type = NETLINK_TYPE_ETHER_ADDR }, + [IFLA_IFNAME] = { .type = NETLINK_TYPE_STRING, .size = IFNAMSIZ - 1 }, + [IFLA_MTU] = { .type = NETLINK_TYPE_U32 }, + [IFLA_LINK] = { .type = NETLINK_TYPE_U32 }, + [IFLA_QDISC] = { .type = NETLINK_TYPE_STRING }, + [IFLA_STATS] = { .size = sizeof(struct rtnl_link_stats) }, +/* + [IFLA_COST], + [IFLA_PRIORITY], +*/ + [IFLA_MASTER] = { .type = NETLINK_TYPE_U32 }, +/* + [IFLA_WIRELESS], +*/ + [IFLA_PROTINFO] = { .type = NETLINK_TYPE_UNION, .type_system_union = &rtnl_prot_info_type_system_union }, + [IFLA_TXQLEN] = { .type = NETLINK_TYPE_U32 }, +/* + [IFLA_MAP] = { .len = sizeof(struct rtnl_link_ifmap) }, +*/ + [IFLA_WEIGHT] = { .type = NETLINK_TYPE_U32 }, + [IFLA_OPERSTATE] = { .type = NETLINK_TYPE_U8 }, + [IFLA_LINKMODE] = { .type = NETLINK_TYPE_U8 }, + [IFLA_LINKINFO] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_link_info_type_system }, + [IFLA_NET_NS_PID] = { .type = NETLINK_TYPE_U32 }, + [IFLA_IFALIAS] = { .type = NETLINK_TYPE_STRING, .size = IFALIASZ - 1 }, + [IFLA_NUM_VF] = { .type = NETLINK_TYPE_U32 }, + [IFLA_VFINFO_LIST] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_vfinfo_list_type_system }, + [IFLA_STATS64] = { .size = sizeof(struct rtnl_link_stats64) }, +/* + [IFLA_VF_PORTS] = { .type = NETLINK_TYPE_NESTED }, + [IFLA_PORT_SELF] = { .type = NETLINK_TYPE_NESTED }, +*/ + [IFLA_AF_SPEC] = { .type = NETLINK_TYPE_UNION, .type_system_union = &rtnl_af_spec_type_system_union }, +/* + [IFLA_VF_PORTS], + [IFLA_PORT_SELF], +*/ + [IFLA_GROUP] = { .type = NETLINK_TYPE_U32 }, + [IFLA_NET_NS_FD] = { .type = NETLINK_TYPE_U32 }, + [IFLA_EXT_MASK] = { .type = NETLINK_TYPE_U32 }, + [IFLA_PROMISCUITY] = { .type = NETLINK_TYPE_U32 }, + [IFLA_NUM_TX_QUEUES] = { .type = NETLINK_TYPE_U32 }, + [IFLA_NUM_RX_QUEUES] = { .type = NETLINK_TYPE_U32 }, + [IFLA_GSO_MAX_SEGS] = { .type = NETLINK_TYPE_U32 }, + [IFLA_GSO_MAX_SIZE] = { .type = NETLINK_TYPE_U32 }, + [IFLA_CARRIER] = { .type = NETLINK_TYPE_U8 }, +/* + [IFLA_PHYS_PORT_ID] = { .type = NETLINK_TYPE_BINARY, .len = MAX_PHYS_PORT_ID_LEN }, +*/ + [IFLA_MIN_MTU] = { .type = NETLINK_TYPE_U32 }, + [IFLA_MAX_MTU] = { .type = NETLINK_TYPE_U32 }, + [IFLA_PROP_LIST] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_prop_list_type_system }, + [IFLA_ALT_IFNAME] = { .type = NETLINK_TYPE_STRING, .size = ALTIFNAMSIZ - 1 }, +}; + +DEFINE_TYPE_SYSTEM(rtnl_link); + +/* IFA_FLAGS was defined in kernel 3.14, but we still support older + * kernels where IFA_MAX is lower. */ +static const NLType rtnl_address_types[] = { + [IFA_ADDRESS] = { .type = NETLINK_TYPE_IN_ADDR }, + [IFA_LOCAL] = { .type = NETLINK_TYPE_IN_ADDR }, + [IFA_LABEL] = { .type = NETLINK_TYPE_STRING, .size = IFNAMSIZ - 1 }, + [IFA_BROADCAST] = { .type = NETLINK_TYPE_IN_ADDR }, + [IFA_ANYCAST] = { .type = NETLINK_TYPE_IN_ADDR }, + [IFA_CACHEINFO] = { .type = NETLINK_TYPE_CACHE_INFO, .size = sizeof(struct ifa_cacheinfo) }, + [IFA_MULTICAST] = { .type = NETLINK_TYPE_IN_ADDR }, + [IFA_FLAGS] = { .type = NETLINK_TYPE_U32 }, + [IFA_RT_PRIORITY] = { .type = NETLINK_TYPE_U32 }, + [IFA_TARGET_NETNSID] = { .type = NETLINK_TYPE_S32 }, +}; + +DEFINE_TYPE_SYSTEM(rtnl_address); + +/* RTM_METRICS --- array of struct rtattr with types of RTAX_* */ + +static const NLType rtnl_route_metrics_types[] = { + [RTAX_MTU] = { .type = NETLINK_TYPE_U32 }, + [RTAX_WINDOW] = { .type = NETLINK_TYPE_U32 }, + [RTAX_RTT] = { .type = NETLINK_TYPE_U32 }, + [RTAX_RTTVAR] = { .type = NETLINK_TYPE_U32 }, + [RTAX_SSTHRESH] = { .type = NETLINK_TYPE_U32 }, + [RTAX_CWND] = { .type = NETLINK_TYPE_U32 }, + [RTAX_ADVMSS] = { .type = NETLINK_TYPE_U32 }, + [RTAX_REORDERING] = { .type = NETLINK_TYPE_U32 }, + [RTAX_HOPLIMIT] = { .type = NETLINK_TYPE_U32 }, + [RTAX_INITCWND] = { .type = NETLINK_TYPE_U32 }, + [RTAX_FEATURES] = { .type = NETLINK_TYPE_U32 }, + [RTAX_RTO_MIN] = { .type = NETLINK_TYPE_U32 }, + [RTAX_INITRWND] = { .type = NETLINK_TYPE_U32 }, + [RTAX_QUICKACK] = { .type = NETLINK_TYPE_U32 }, + [RTAX_CC_ALGO] = { .type = NETLINK_TYPE_U32 }, + [RTAX_FASTOPEN_NO_COOKIE] = { .type = NETLINK_TYPE_U32 }, +}; + +DEFINE_TYPE_SYSTEM(rtnl_route_metrics); + +static const NLType rtnl_route_types[] = { + [RTA_DST] = { .type = NETLINK_TYPE_IN_ADDR }, /* 6? */ + [RTA_SRC] = { .type = NETLINK_TYPE_IN_ADDR }, /* 6? */ + [RTA_IIF] = { .type = NETLINK_TYPE_U32 }, + [RTA_OIF] = { .type = NETLINK_TYPE_U32 }, + [RTA_GATEWAY] = { .type = NETLINK_TYPE_IN_ADDR }, + [RTA_PRIORITY] = { .type = NETLINK_TYPE_U32 }, + [RTA_PREFSRC] = { .type = NETLINK_TYPE_IN_ADDR }, /* 6? */ + [RTA_METRICS] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_route_metrics_type_system}, + [RTA_MULTIPATH] = { .size = sizeof(struct rtnexthop) }, + [RTA_FLOW] = { .type = NETLINK_TYPE_U32 }, /* 6? */ + [RTA_CACHEINFO] = { .size = sizeof(struct rta_cacheinfo) }, + [RTA_TABLE] = { .type = NETLINK_TYPE_U32 }, + [RTA_MARK] = { .type = NETLINK_TYPE_U32 }, + [RTA_MFC_STATS] = { .type = NETLINK_TYPE_U64 }, + [RTA_VIA] = { /* See struct rtvia */ }, + [RTA_NEWDST] = { .type = NETLINK_TYPE_U32 }, + [RTA_PREF] = { .type = NETLINK_TYPE_U8 }, + [RTA_ENCAP_TYPE] = { .type = NETLINK_TYPE_U16 }, + [RTA_ENCAP] = { .type = NETLINK_TYPE_NESTED }, /* Multiple type systems i.e. LWTUNNEL_ENCAP_MPLS/LWTUNNEL_ENCAP_IP/LWTUNNEL_ENCAP_ILA etc... */ + [RTA_EXPIRES] = { .type = NETLINK_TYPE_U32 }, + [RTA_UID] = { .type = NETLINK_TYPE_U32 }, + [RTA_TTL_PROPAGATE] = { .type = NETLINK_TYPE_U8 }, + [RTA_IP_PROTO] = { .type = NETLINK_TYPE_U8 }, + [RTA_SPORT] = { .type = NETLINK_TYPE_U16 }, + [RTA_DPORT] = { .type = NETLINK_TYPE_U16 }, + [RTA_NH_ID] = { .type = NETLINK_TYPE_U32 }, +}; + +DEFINE_TYPE_SYSTEM(rtnl_route); + +static const NLType rtnl_neigh_types[] = { + [NDA_DST] = { .type = NETLINK_TYPE_IN_ADDR }, + [NDA_LLADDR] = { /* struct ether_addr, struct in_addr, or struct in6_addr */ }, + [NDA_CACHEINFO] = { .type = NETLINK_TYPE_CACHE_INFO, .size = sizeof(struct nda_cacheinfo) }, + [NDA_PROBES] = { .type = NETLINK_TYPE_U32 }, + [NDA_VLAN] = { .type = NETLINK_TYPE_U16 }, + [NDA_PORT] = { .type = NETLINK_TYPE_U16 }, + [NDA_VNI] = { .type = NETLINK_TYPE_U32 }, + [NDA_IFINDEX] = { .type = NETLINK_TYPE_U32 }, +}; + +DEFINE_TYPE_SYSTEM(rtnl_neigh); + +static const NLType rtnl_addrlabel_types[] = { + [IFAL_ADDRESS] = { .type = NETLINK_TYPE_IN_ADDR, .size = sizeof(struct in6_addr) }, + [IFAL_LABEL] = { .type = NETLINK_TYPE_U32 }, +}; + +DEFINE_TYPE_SYSTEM(rtnl_addrlabel); + +static const NLType rtnl_routing_policy_rule_types[] = { + [FRA_DST] = { .type = NETLINK_TYPE_IN_ADDR }, + [FRA_SRC] = { .type = NETLINK_TYPE_IN_ADDR }, + [FRA_IIFNAME] = { .type = NETLINK_TYPE_STRING }, + [FRA_GOTO] = { .type = NETLINK_TYPE_U32 }, + [FRA_PRIORITY] = { .type = NETLINK_TYPE_U32 }, + [FRA_FWMARK] = { .type = NETLINK_TYPE_U32 }, + [FRA_FLOW] = { .type = NETLINK_TYPE_U32 }, + [FRA_TUN_ID] = { .type = NETLINK_TYPE_U64 }, + [FRA_SUPPRESS_IFGROUP] = { .type = NETLINK_TYPE_U32 }, + [FRA_SUPPRESS_PREFIXLEN] = { .type = NETLINK_TYPE_U32 }, + [FRA_TABLE] = { .type = NETLINK_TYPE_U32 }, + [FRA_FWMASK] = { .type = NETLINK_TYPE_U32 }, + [FRA_OIFNAME] = { .type = NETLINK_TYPE_STRING }, + [FRA_PAD] = { .type = NETLINK_TYPE_U32 }, + [FRA_L3MDEV] = { .type = NETLINK_TYPE_U8 }, + [FRA_UID_RANGE] = { .size = sizeof(struct fib_rule_uid_range) }, + [FRA_PROTOCOL] = { .type = NETLINK_TYPE_U8 }, + [FRA_IP_PROTO] = { .type = NETLINK_TYPE_U8 }, + [FRA_SPORT_RANGE] = { .size = sizeof(struct fib_rule_port_range) }, + [FRA_DPORT_RANGE] = { .size = sizeof(struct fib_rule_port_range) }, +}; + +DEFINE_TYPE_SYSTEM(rtnl_routing_policy_rule); + +static const NLType rtnl_nexthop_types[] = { + [NHA_ID] = { .type = NETLINK_TYPE_U32 }, + [NHA_GROUP] = { /* array of struct nexthop_grp */ }, + [NHA_GROUP_TYPE] = { .type = NETLINK_TYPE_U16 }, + [NHA_BLACKHOLE] = { .type = NETLINK_TYPE_FLAG }, + [NHA_OIF] = { .type = NETLINK_TYPE_U32 }, + [NHA_GATEWAY] = { .type = NETLINK_TYPE_IN_ADDR }, + [NHA_ENCAP_TYPE] = { .type = NETLINK_TYPE_U16 }, + [NHA_ENCAP] = { .type = NETLINK_TYPE_NESTED }, + [NHA_GROUPS] = { .type = NETLINK_TYPE_FLAG }, + [NHA_MASTER] = { .type = NETLINK_TYPE_U32 }, + [NHA_FDB] = { .type = NETLINK_TYPE_FLAG }, +}; + +DEFINE_TYPE_SYSTEM(rtnl_nexthop); + +static const NLType rtnl_tca_option_data_cake_types[] = { + [TCA_CAKE_BASE_RATE64] = { .type = NETLINK_TYPE_U64 }, + [TCA_CAKE_OVERHEAD] = { .type = NETLINK_TYPE_S32 }, + [TCA_CAKE_MPU] = { .type = NETLINK_TYPE_U32 }, +}; + +static const NLType rtnl_tca_option_data_codel_types[] = { + [TCA_CODEL_TARGET] = { .type = NETLINK_TYPE_U32 }, + [TCA_CODEL_LIMIT] = { .type = NETLINK_TYPE_U32 }, + [TCA_CODEL_INTERVAL] = { .type = NETLINK_TYPE_U32 }, + [TCA_CODEL_ECN] = { .type = NETLINK_TYPE_U32 }, + [TCA_CODEL_CE_THRESHOLD] = { .type = NETLINK_TYPE_U32 }, +}; + +static const NLType rtnl_tca_option_data_drr_types[] = { + [TCA_DRR_QUANTUM] = { .type = NETLINK_TYPE_U32 }, +}; + +static const NLType rtnl_tca_option_data_ets_quanta_types[] = { + [TCA_ETS_QUANTA_BAND] = { .type = NETLINK_TYPE_U32, }, +}; + +DEFINE_TYPE_SYSTEM(rtnl_tca_option_data_ets_quanta); + +static const NLType rtnl_tca_option_data_ets_prio_types[] = { + [TCA_ETS_PRIOMAP_BAND] = { .type = NETLINK_TYPE_U8, }, +}; + +DEFINE_TYPE_SYSTEM(rtnl_tca_option_data_ets_prio); + +static const NLType rtnl_tca_option_data_ets_types[] = { + [TCA_ETS_NBANDS] = { .type = NETLINK_TYPE_U8 }, + [TCA_ETS_NSTRICT] = { .type = NETLINK_TYPE_U8 }, + [TCA_ETS_QUANTA] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_tca_option_data_ets_quanta_type_system }, + [TCA_ETS_PRIOMAP] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_tca_option_data_ets_prio_type_system }, + [TCA_ETS_QUANTA_BAND] = { .type = NETLINK_TYPE_U32 }, +}; + +static const NLType rtnl_tca_option_data_fq_types[] = { + [TCA_FQ_PLIMIT] = { .type = NETLINK_TYPE_U32 }, + [TCA_FQ_FLOW_PLIMIT] = { .type = NETLINK_TYPE_U32 }, + [TCA_FQ_QUANTUM] = { .type = NETLINK_TYPE_U32 }, + [TCA_FQ_INITIAL_QUANTUM] = { .type = NETLINK_TYPE_U32 }, + [TCA_FQ_RATE_ENABLE] = { .type = NETLINK_TYPE_U32 }, + [TCA_FQ_FLOW_DEFAULT_RATE] = { .type = NETLINK_TYPE_U32 }, + [TCA_FQ_FLOW_MAX_RATE] = { .type = NETLINK_TYPE_U32 }, + [TCA_FQ_BUCKETS_LOG] = { .type = NETLINK_TYPE_U32 }, + [TCA_FQ_FLOW_REFILL_DELAY] = { .type = NETLINK_TYPE_U32 }, + [TCA_FQ_LOW_RATE_THRESHOLD] = { .type = NETLINK_TYPE_U32 }, + [TCA_FQ_CE_THRESHOLD] = { .type = NETLINK_TYPE_U32 }, + [TCA_FQ_ORPHAN_MASK] = { .type = NETLINK_TYPE_U32 }, +}; + +static const NLType rtnl_tca_option_data_fq_codel_types[] = { + [TCA_FQ_CODEL_TARGET] = { .type = NETLINK_TYPE_U32 }, + [TCA_FQ_CODEL_LIMIT] = { .type = NETLINK_TYPE_U32 }, + [TCA_FQ_CODEL_INTERVAL] = { .type = NETLINK_TYPE_U32 }, + [TCA_FQ_CODEL_ECN] = { .type = NETLINK_TYPE_U32 }, + [TCA_FQ_CODEL_FLOWS] = { .type = NETLINK_TYPE_U32 }, + [TCA_FQ_CODEL_QUANTUM] = { .type = NETLINK_TYPE_U32 }, + [TCA_FQ_CODEL_CE_THRESHOLD] = { .type = NETLINK_TYPE_U32 }, + [TCA_FQ_CODEL_DROP_BATCH_SIZE] = { .type = NETLINK_TYPE_U32 }, + [TCA_FQ_CODEL_MEMORY_LIMIT] = { .type = NETLINK_TYPE_U32 }, +}; + +static const NLType rtnl_tca_option_data_fq_pie_types[] = { + [TCA_FQ_PIE_LIMIT] = { .type = NETLINK_TYPE_U32 }, +}; + +static const NLType rtnl_tca_option_data_gred_types[] = { + [TCA_GRED_DPS] = { .size = sizeof(struct tc_gred_sopt) }, +}; + +static const NLType rtnl_tca_option_data_hhf_types[] = { + [TCA_HHF_BACKLOG_LIMIT] = { .type = NETLINK_TYPE_U32 }, +}; + +static const NLType rtnl_tca_option_data_htb_types[] = { + [TCA_HTB_PARMS] = { .size = sizeof(struct tc_htb_opt) }, + [TCA_HTB_INIT] = { .size = sizeof(struct tc_htb_glob) }, + [TCA_HTB_CTAB] = { .size = TC_RTAB_SIZE }, + [TCA_HTB_RTAB] = { .size = TC_RTAB_SIZE }, + [TCA_HTB_RATE64] = { .type = NETLINK_TYPE_U64 }, + [TCA_HTB_CEIL64] = { .type = NETLINK_TYPE_U64 }, +}; + +static const NLType rtnl_tca_option_data_pie_types[] = { + [TCA_PIE_LIMIT] = { .type = NETLINK_TYPE_U32 }, +}; + +static const NLType rtnl_tca_option_data_qfq_types[] = { + [TCA_QFQ_WEIGHT] = { .type = NETLINK_TYPE_U32 }, + [TCA_QFQ_LMAX] = { .type = NETLINK_TYPE_U32 }, +}; + +static const NLType rtnl_tca_option_data_sfb_types[] = { + [TCA_SFB_PARMS] = { .size = sizeof(struct tc_sfb_qopt) }, +}; + +static const NLType rtnl_tca_option_data_tbf_types[] = { + [TCA_TBF_PARMS] = { .size = sizeof(struct tc_tbf_qopt) }, + [TCA_TBF_RTAB] = { .size = TC_RTAB_SIZE }, + [TCA_TBF_PTAB] = { .size = TC_RTAB_SIZE }, + [TCA_TBF_RATE64] = { .type = NETLINK_TYPE_U64 }, + [TCA_TBF_PRATE64] = { .type = NETLINK_TYPE_U64 }, + [TCA_TBF_BURST] = { .type = NETLINK_TYPE_U32 }, + [TCA_TBF_PBURST] = { .type = NETLINK_TYPE_U32 }, +}; + +static const NLTypeSystemUnionElement rtnl_tca_option_data_type_systems[] = { + { .name = "cake", .type_system = TYPE_SYSTEM_FROM_TYPE(rtnl_tca_option_data_cake), }, + { .name = "codel", .type_system = TYPE_SYSTEM_FROM_TYPE(rtnl_tca_option_data_codel), }, + { .name = "drr", .type_system = TYPE_SYSTEM_FROM_TYPE(rtnl_tca_option_data_drr), }, + { .name = "ets", .type_system = TYPE_SYSTEM_FROM_TYPE(rtnl_tca_option_data_ets), }, + { .name = "fq", .type_system = TYPE_SYSTEM_FROM_TYPE(rtnl_tca_option_data_fq), }, + { .name = "fq_codel", .type_system = TYPE_SYSTEM_FROM_TYPE(rtnl_tca_option_data_fq_codel), }, + { .name = "fq_pie", .type_system = TYPE_SYSTEM_FROM_TYPE(rtnl_tca_option_data_fq_pie), }, + { .name = "gred", .type_system = TYPE_SYSTEM_FROM_TYPE(rtnl_tca_option_data_gred), }, + { .name = "hhf", .type_system = TYPE_SYSTEM_FROM_TYPE(rtnl_tca_option_data_hhf), }, + { .name = "htb", .type_system = TYPE_SYSTEM_FROM_TYPE(rtnl_tca_option_data_htb), }, + { .name = "pie", .type_system = TYPE_SYSTEM_FROM_TYPE(rtnl_tca_option_data_pie), }, + { .name = "qfq", .type_system = TYPE_SYSTEM_FROM_TYPE(rtnl_tca_option_data_qfq), }, + { .name = "sfb", .type_system = TYPE_SYSTEM_FROM_TYPE(rtnl_tca_option_data_sfb), }, + { .name = "tbf", .type_system = TYPE_SYSTEM_FROM_TYPE(rtnl_tca_option_data_tbf), }, +}; + +DEFINE_TYPE_SYSTEM_UNION_MATCH_SIBLING(rtnl_tca_option_data, TCA_KIND); + +static const NLType rtnl_tca_types[] = { + [TCA_KIND] = { .type = NETLINK_TYPE_STRING }, + [TCA_OPTIONS] = { .type = NETLINK_TYPE_UNION, .type_system_union = &rtnl_tca_option_data_type_system_union }, + [TCA_INGRESS_BLOCK] = { .type = NETLINK_TYPE_U32 }, + [TCA_EGRESS_BLOCK] = { .type = NETLINK_TYPE_U32 }, +}; + +DEFINE_TYPE_SYSTEM(rtnl_tca); + +static const NLType rtnl_mdb_types[] = { + [MDBA_SET_ENTRY] = { .size = sizeof(struct br_port_msg) }, +}; + +DEFINE_TYPE_SYSTEM(rtnl_mdb); + +static const NLType rtnl_types[] = { + [RTM_NEWLINK] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_link_type_system, .size = sizeof(struct ifinfomsg) }, + [RTM_DELLINK] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_link_type_system, .size = sizeof(struct ifinfomsg) }, + [RTM_GETLINK] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_link_type_system, .size = sizeof(struct ifinfomsg) }, + [RTM_SETLINK] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_link_type_system, .size = sizeof(struct ifinfomsg) }, + [RTM_NEWLINKPROP] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_link_type_system, .size = sizeof(struct ifinfomsg) }, + [RTM_DELLINKPROP] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_link_type_system, .size = sizeof(struct ifinfomsg) }, + [RTM_GETLINKPROP] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_link_type_system, .size = sizeof(struct ifinfomsg) }, + [RTM_NEWADDR] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_address_type_system, .size = sizeof(struct ifaddrmsg) }, + [RTM_DELADDR] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_address_type_system, .size = sizeof(struct ifaddrmsg) }, + [RTM_GETADDR] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_address_type_system, .size = sizeof(struct ifaddrmsg) }, + [RTM_NEWROUTE] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_route_type_system, .size = sizeof(struct rtmsg) }, + [RTM_DELROUTE] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_route_type_system, .size = sizeof(struct rtmsg) }, + [RTM_GETROUTE] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_route_type_system, .size = sizeof(struct rtmsg) }, + [RTM_NEWNEIGH] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_neigh_type_system, .size = sizeof(struct ndmsg) }, + [RTM_DELNEIGH] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_neigh_type_system, .size = sizeof(struct ndmsg) }, + [RTM_GETNEIGH] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_neigh_type_system, .size = sizeof(struct ndmsg) }, + [RTM_NEWADDRLABEL] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_addrlabel_type_system, .size = sizeof(struct ifaddrlblmsg) }, + [RTM_DELADDRLABEL] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_addrlabel_type_system, .size = sizeof(struct ifaddrlblmsg) }, + [RTM_GETADDRLABEL] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_addrlabel_type_system, .size = sizeof(struct ifaddrlblmsg) }, + [RTM_NEWRULE] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_routing_policy_rule_type_system, .size = sizeof(struct fib_rule_hdr) }, + [RTM_DELRULE] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_routing_policy_rule_type_system, .size = sizeof(struct fib_rule_hdr) }, + [RTM_GETRULE] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_routing_policy_rule_type_system, .size = sizeof(struct fib_rule_hdr) }, + [RTM_NEWNEXTHOP] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_nexthop_type_system, .size = sizeof(struct nhmsg) }, + [RTM_DELNEXTHOP] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_nexthop_type_system, .size = sizeof(struct nhmsg) }, + [RTM_GETNEXTHOP] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_nexthop_type_system, .size = sizeof(struct nhmsg) }, + [RTM_NEWQDISC] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_tca_type_system, .size = sizeof(struct tcmsg) }, + [RTM_DELQDISC] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_tca_type_system, .size = sizeof(struct tcmsg) }, + [RTM_GETQDISC] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_tca_type_system, .size = sizeof(struct tcmsg) }, + [RTM_NEWTCLASS] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_tca_type_system, .size = sizeof(struct tcmsg) }, + [RTM_DELTCLASS] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_tca_type_system, .size = sizeof(struct tcmsg) }, + [RTM_GETTCLASS] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_tca_type_system, .size = sizeof(struct tcmsg) }, + [RTM_NEWMDB] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_mdb_type_system, .size = sizeof(struct br_port_msg) }, + [RTM_DELMDB] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_mdb_type_system, .size = sizeof(struct br_port_msg) }, + [RTM_GETMDB] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_mdb_type_system, .size = sizeof(struct br_port_msg) }, +}; + +DEFINE_TYPE_SYSTEM(rtnl); + +const NLType *rtnl_get_type(uint16_t nlmsg_type) { + return type_system_get_type(&rtnl_type_system, nlmsg_type); +} diff --git a/src/libsystemd/sd-netlink/netlink-types.c b/src/libsystemd/sd-netlink/netlink-types.c index beb926d40b..051dac95c2 100644 --- a/src/libsystemd/sd-netlink/netlink-types.c +++ b/src/libsystemd/sd-netlink/netlink-types.c @@ -1,1694 +1,30 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ -#include <netinet/in.h> -#include <stdint.h> -#include <sys/socket.h> -#include <linux/can/vxcan.h> #include <linux/netlink.h> -#include <linux/rtnetlink.h> -#include <linux/genetlink.h> -#include <linux/ip.h> -#include <linux/if.h> -#include <linux/batman_adv.h> -#include <linux/can/netlink.h> -#include <linux/fib_rules.h> -#include <linux/fou.h> -#include <linux/if_addr.h> -#include <linux/if_addrlabel.h> -#include <linux/if_bridge.h> -#include <linux/if_link.h> -#include <linux/if_macsec.h> -#include <linux/if_tunnel.h> -#include <linux/l2tp.h> -#include <linux/netfilter/nf_tables.h> -#include <linux/netfilter/nfnetlink.h> -#include <linux/nexthop.h> -#include <linux/nl80211.h> -#include <linux/pkt_sched.h> -#include <linux/veth.h> -#include <linux/wireguard.h> -#include "sd-netlink.h" - -#include "generic-netlink.h" -#include "hashmap.h" -#include "macro.h" +#include "netlink-genl.h" #include "netlink-internal.h" -#include "netlink-types.h" -#include "string-table.h" -#include "util.h" - -/* Maximum ARP IP target defined in kernel */ -#define BOND_MAX_ARP_TARGETS 16 - -typedef enum { - BOND_ARP_TARGETS_0, - BOND_ARP_TARGETS_1, - BOND_ARP_TARGETS_2, - BOND_ARP_TARGETS_3, - BOND_ARP_TARGETS_4, - BOND_ARP_TARGETS_5, - BOND_ARP_TARGETS_6, - BOND_ARP_TARGETS_7, - BOND_ARP_TARGETS_8, - BOND_ARP_TARGETS_9, - BOND_ARP_TARGETS_10, - BOND_ARP_TARGETS_11, - BOND_ARP_TARGETS_12, - BOND_ARP_TARGETS_13, - BOND_ARP_TARGETS_14, - BOND_ARP_TARGETS_MAX = BOND_MAX_ARP_TARGETS, -} BondArpTargets; - -struct NLType { - uint16_t type; - size_t size; - const NLTypeSystem *type_system; - const NLTypeSystemUnion *type_system_union; -}; - -struct NLTypeSystem { - uint16_t count; - const NLType *types; -}; - -static const NLTypeSystem rtnl_link_type_system; +#include "netlink-types-internal.h" static const NLType empty_types[1] = { /* fake array to avoid .types==NULL, which denotes invalid type-systems */ }; -static const NLTypeSystem empty_type_system = { - .count = 0, - .types = empty_types, -}; - -static const NLType rtnl_link_info_data_batadv_types[] = { - [IFLA_BATADV_ALGO_NAME] = { .type = NETLINK_TYPE_STRING, .size = 20 }, -}; - -static const NLType rtnl_link_info_data_veth_types[] = { - [VETH_INFO_PEER] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_link_type_system, .size = sizeof(struct ifinfomsg) }, -}; - -static const NLType rtnl_link_info_data_vxcan_types[] = { - [VXCAN_INFO_PEER] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_link_type_system, .size = sizeof(struct ifinfomsg) }, -}; - -static const NLType rtnl_link_info_data_ipvlan_types[] = { - [IFLA_IPVLAN_MODE] = { .type = NETLINK_TYPE_U16 }, - [IFLA_IPVLAN_FLAGS] = { .type = NETLINK_TYPE_U16 }, -}; - -static const NLType rtnl_macvlan_macaddr_types[] = { - [IFLA_MACVLAN_MACADDR] = { .type = NETLINK_TYPE_ETHER_ADDR }, -}; - -static const NLTypeSystem rtnl_macvlan_macaddr_type_system = { - .count = ELEMENTSOF(rtnl_macvlan_macaddr_types), - .types = rtnl_macvlan_macaddr_types, -}; - -static const NLType rtnl_link_info_data_macvlan_types[] = { - [IFLA_MACVLAN_MODE] = { .type = NETLINK_TYPE_U32 }, - [IFLA_MACVLAN_FLAGS] = { .type = NETLINK_TYPE_U16 }, - [IFLA_MACVLAN_MACADDR_MODE] = { .type = NETLINK_TYPE_U32 }, - [IFLA_MACVLAN_MACADDR_DATA] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_macvlan_macaddr_type_system }, - [IFLA_MACVLAN_MACADDR_COUNT] = { .type = NETLINK_TYPE_U32 }, - [IFLA_MACVLAN_BC_QUEUE_LEN] = { .type = NETLINK_TYPE_U32 }, - [IFLA_MACVLAN_BC_QUEUE_LEN_USED] = { .type = NETLINK_TYPE_REJECT }, -}; - -static const NLType rtnl_link_info_data_bridge_types[] = { - [IFLA_BR_FORWARD_DELAY] = { .type = NETLINK_TYPE_U32 }, - [IFLA_BR_HELLO_TIME] = { .type = NETLINK_TYPE_U32 }, - [IFLA_BR_MAX_AGE] = { .type = NETLINK_TYPE_U32 }, - [IFLA_BR_AGEING_TIME] = { .type = NETLINK_TYPE_U32 }, - [IFLA_BR_STP_STATE] = { .type = NETLINK_TYPE_U32 }, - [IFLA_BR_PRIORITY] = { .type = NETLINK_TYPE_U16 }, - [IFLA_BR_VLAN_FILTERING] = { .type = NETLINK_TYPE_U8 }, - [IFLA_BR_VLAN_PROTOCOL] = { .type = NETLINK_TYPE_U16 }, - [IFLA_BR_GROUP_FWD_MASK] = { .type = NETLINK_TYPE_U16 }, - [IFLA_BR_ROOT_PORT] = { .type = NETLINK_TYPE_U16 }, - [IFLA_BR_ROOT_PATH_COST] = { .type = NETLINK_TYPE_U32 }, - [IFLA_BR_TOPOLOGY_CHANGE] = { .type = NETLINK_TYPE_U8 }, - [IFLA_BR_TOPOLOGY_CHANGE_DETECTED] = { .type = NETLINK_TYPE_U8 }, - [IFLA_BR_HELLO_TIMER] = { .type = NETLINK_TYPE_U16 }, - [IFLA_BR_TCN_TIMER] = { .type = NETLINK_TYPE_U16 }, - [IFLA_BR_TOPOLOGY_CHANGE_TIMER] = { .type = NETLINK_TYPE_U16 }, - [IFLA_BR_GC_TIMER] = { .type = NETLINK_TYPE_U64 }, - [IFLA_BR_GROUP_ADDR] = { .type = NETLINK_TYPE_U16 }, - [IFLA_BR_FDB_FLUSH] = { .type = NETLINK_TYPE_U16 }, - [IFLA_BR_MCAST_ROUTER] = { .type = NETLINK_TYPE_U8 }, - [IFLA_BR_MCAST_SNOOPING] = { .type = NETLINK_TYPE_U8 }, - [IFLA_BR_MCAST_QUERY_USE_IFADDR] = { .type = NETLINK_TYPE_U8 }, - [IFLA_BR_MCAST_QUERIER] = { .type = NETLINK_TYPE_U8 }, - [IFLA_BR_MCAST_HASH_ELASTICITY] = { .type = NETLINK_TYPE_U32 }, - [IFLA_BR_MCAST_HASH_MAX] = { .type = NETLINK_TYPE_U16 }, - [IFLA_BR_MCAST_LAST_MEMBER_CNT] = { .type = NETLINK_TYPE_U32 }, - [IFLA_BR_MCAST_STARTUP_QUERY_CNT] = { .type = NETLINK_TYPE_U16 }, - [IFLA_BR_MCAST_LAST_MEMBER_INTVL] = { .type = NETLINK_TYPE_U64 }, - [IFLA_BR_MCAST_MEMBERSHIP_INTVL] = { .type = NETLINK_TYPE_U64 }, - [IFLA_BR_MCAST_QUERIER_INTVL] = { .type = NETLINK_TYPE_U64 }, - [IFLA_BR_MCAST_QUERY_INTVL] = { .type = NETLINK_TYPE_U64 }, - [IFLA_BR_MCAST_QUERY_RESPONSE_INTVL] = { .type = NETLINK_TYPE_U64 }, - [IFLA_BR_MCAST_STARTUP_QUERY_INTVL] = { .type = NETLINK_TYPE_U64 }, - [IFLA_BR_NF_CALL_IPTABLES] = { .type = NETLINK_TYPE_U8 }, - [IFLA_BR_NF_CALL_IP6TABLES] = { .type = NETLINK_TYPE_U8 }, - [IFLA_BR_NF_CALL_ARPTABLES] = { .type = NETLINK_TYPE_U8 }, - [IFLA_BR_VLAN_DEFAULT_PVID] = { .type = NETLINK_TYPE_U16 }, - [IFLA_BR_MCAST_IGMP_VERSION] = { .type = NETLINK_TYPE_U8 }, -}; - -static const NLType rtnl_vlan_qos_map_types[] = { - [IFLA_VLAN_QOS_MAPPING] = { .size = sizeof(struct ifla_vlan_qos_mapping) }, -}; - -static const NLTypeSystem rtnl_vlan_qos_map_type_system = { - .count = ELEMENTSOF(rtnl_vlan_qos_map_types), - .types = rtnl_vlan_qos_map_types, -}; - -static const NLType rtnl_link_info_data_vlan_types[] = { - [IFLA_VLAN_ID] = { .type = NETLINK_TYPE_U16 }, - [IFLA_VLAN_FLAGS] = { .size = sizeof(struct ifla_vlan_flags) }, - [IFLA_VLAN_EGRESS_QOS] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_vlan_qos_map_type_system }, - [IFLA_VLAN_INGRESS_QOS] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_vlan_qos_map_type_system }, - [IFLA_VLAN_PROTOCOL] = { .type = NETLINK_TYPE_U16 }, -}; - -static const NLType rtnl_link_info_data_vxlan_types[] = { - [IFLA_VXLAN_ID] = { .type = NETLINK_TYPE_U32 }, - [IFLA_VXLAN_GROUP] = { .type = NETLINK_TYPE_IN_ADDR }, - [IFLA_VXLAN_LINK] = { .type = NETLINK_TYPE_U32 }, - [IFLA_VXLAN_LOCAL] = { .type = NETLINK_TYPE_IN_ADDR }, - [IFLA_VXLAN_TTL] = { .type = NETLINK_TYPE_U8 }, - [IFLA_VXLAN_TOS] = { .type = NETLINK_TYPE_U8 }, - [IFLA_VXLAN_LEARNING] = { .type = NETLINK_TYPE_U8 }, - [IFLA_VXLAN_AGEING] = { .type = NETLINK_TYPE_U32 }, - [IFLA_VXLAN_LIMIT] = { .type = NETLINK_TYPE_U32 }, - [IFLA_VXLAN_PORT_RANGE] = { .type = NETLINK_TYPE_U32}, - [IFLA_VXLAN_PROXY] = { .type = NETLINK_TYPE_U8 }, - [IFLA_VXLAN_RSC] = { .type = NETLINK_TYPE_U8 }, - [IFLA_VXLAN_L2MISS] = { .type = NETLINK_TYPE_U8 }, - [IFLA_VXLAN_L3MISS] = { .type = NETLINK_TYPE_U8 }, - [IFLA_VXLAN_PORT] = { .type = NETLINK_TYPE_U16 }, - [IFLA_VXLAN_GROUP6] = { .type = NETLINK_TYPE_IN_ADDR }, - [IFLA_VXLAN_LOCAL6] = { .type = NETLINK_TYPE_IN_ADDR }, - [IFLA_VXLAN_UDP_CSUM] = { .type = NETLINK_TYPE_U8 }, - [IFLA_VXLAN_UDP_ZERO_CSUM6_TX] = { .type = NETLINK_TYPE_U8 }, - [IFLA_VXLAN_UDP_ZERO_CSUM6_RX] = { .type = NETLINK_TYPE_U8 }, - [IFLA_VXLAN_REMCSUM_TX] = { .type = NETLINK_TYPE_U8 }, - [IFLA_VXLAN_REMCSUM_RX] = { .type = NETLINK_TYPE_U8 }, - [IFLA_VXLAN_GBP] = { .type = NETLINK_TYPE_FLAG }, - [IFLA_VXLAN_REMCSUM_NOPARTIAL] = { .type = NETLINK_TYPE_FLAG }, - [IFLA_VXLAN_COLLECT_METADATA] = { .type = NETLINK_TYPE_U8 }, - [IFLA_VXLAN_LABEL] = { .type = NETLINK_TYPE_U32 }, - [IFLA_VXLAN_GPE] = { .type = NETLINK_TYPE_FLAG }, - [IFLA_VXLAN_TTL_INHERIT] = { .type = NETLINK_TYPE_FLAG }, - [IFLA_VXLAN_DF] = { .type = NETLINK_TYPE_U8 }, -}; - -static const NLType rtnl_bond_arp_target_types[] = { - [BOND_ARP_TARGETS_0] = { .type = NETLINK_TYPE_U32 }, - [BOND_ARP_TARGETS_1] = { .type = NETLINK_TYPE_U32 }, - [BOND_ARP_TARGETS_2] = { .type = NETLINK_TYPE_U32 }, - [BOND_ARP_TARGETS_3] = { .type = NETLINK_TYPE_U32 }, - [BOND_ARP_TARGETS_4] = { .type = NETLINK_TYPE_U32 }, - [BOND_ARP_TARGETS_5] = { .type = NETLINK_TYPE_U32 }, - [BOND_ARP_TARGETS_6] = { .type = NETLINK_TYPE_U32 }, - [BOND_ARP_TARGETS_7] = { .type = NETLINK_TYPE_U32 }, - [BOND_ARP_TARGETS_8] = { .type = NETLINK_TYPE_U32 }, - [BOND_ARP_TARGETS_9] = { .type = NETLINK_TYPE_U32 }, - [BOND_ARP_TARGETS_10] = { .type = NETLINK_TYPE_U32 }, - [BOND_ARP_TARGETS_11] = { .type = NETLINK_TYPE_U32 }, - [BOND_ARP_TARGETS_12] = { .type = NETLINK_TYPE_U32 }, - [BOND_ARP_TARGETS_13] = { .type = NETLINK_TYPE_U32 }, - [BOND_ARP_TARGETS_14] = { .type = NETLINK_TYPE_U32 }, - [BOND_ARP_TARGETS_MAX] = { .type = NETLINK_TYPE_U32 }, -}; - -static const NLTypeSystem rtnl_bond_arp_type_system = { - .count = ELEMENTSOF(rtnl_bond_arp_target_types), - .types = rtnl_bond_arp_target_types, -}; - -static const NLType rtnl_link_info_data_bond_types[] = { - [IFLA_BOND_MODE] = { .type = NETLINK_TYPE_U8 }, - [IFLA_BOND_ACTIVE_SLAVE] = { .type = NETLINK_TYPE_U32 }, - [IFLA_BOND_MIIMON] = { .type = NETLINK_TYPE_U32 }, - [IFLA_BOND_UPDELAY] = { .type = NETLINK_TYPE_U32 }, - [IFLA_BOND_DOWNDELAY] = { .type = NETLINK_TYPE_U32 }, - [IFLA_BOND_USE_CARRIER] = { .type = NETLINK_TYPE_U8 }, - [IFLA_BOND_ARP_INTERVAL] = { .type = NETLINK_TYPE_U32 }, - [IFLA_BOND_ARP_IP_TARGET] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_bond_arp_type_system }, - [IFLA_BOND_ARP_VALIDATE] = { .type = NETLINK_TYPE_U32 }, - [IFLA_BOND_ARP_ALL_TARGETS] = { .type = NETLINK_TYPE_U32 }, - [IFLA_BOND_PRIMARY] = { .type = NETLINK_TYPE_U32 }, - [IFLA_BOND_PRIMARY_RESELECT] = { .type = NETLINK_TYPE_U8 }, - [IFLA_BOND_FAIL_OVER_MAC] = { .type = NETLINK_TYPE_U8 }, - [IFLA_BOND_XMIT_HASH_POLICY] = { .type = NETLINK_TYPE_U8 }, - [IFLA_BOND_RESEND_IGMP] = { .type = NETLINK_TYPE_U32 }, - [IFLA_BOND_NUM_PEER_NOTIF] = { .type = NETLINK_TYPE_U8 }, - [IFLA_BOND_ALL_SLAVES_ACTIVE] = { .type = NETLINK_TYPE_U8 }, - [IFLA_BOND_MIN_LINKS] = { .type = NETLINK_TYPE_U32 }, - [IFLA_BOND_LP_INTERVAL] = { .type = NETLINK_TYPE_U32 }, - [IFLA_BOND_PACKETS_PER_SLAVE] = { .type = NETLINK_TYPE_U32 }, - [IFLA_BOND_AD_LACP_RATE] = { .type = NETLINK_TYPE_U8 }, - [IFLA_BOND_AD_SELECT] = { .type = NETLINK_TYPE_U8 }, - [IFLA_BOND_AD_INFO] = { .type = NETLINK_TYPE_NESTED }, - [IFLA_BOND_AD_ACTOR_SYS_PRIO] = { .type = NETLINK_TYPE_U16 }, - [IFLA_BOND_AD_USER_PORT_KEY] = { .type = NETLINK_TYPE_U16 }, - [IFLA_BOND_AD_ACTOR_SYSTEM] = { .type = NETLINK_TYPE_ETHER_ADDR }, - [IFLA_BOND_TLB_DYNAMIC_LB] = { .type = NETLINK_TYPE_U8 }, -}; - -static const NLType rtnl_link_info_data_iptun_types[] = { - [IFLA_IPTUN_LINK] = { .type = NETLINK_TYPE_U32 }, - [IFLA_IPTUN_LOCAL] = { .type = NETLINK_TYPE_IN_ADDR }, - [IFLA_IPTUN_REMOTE] = { .type = NETLINK_TYPE_IN_ADDR }, - [IFLA_IPTUN_TTL] = { .type = NETLINK_TYPE_U8 }, - [IFLA_IPTUN_TOS] = { .type = NETLINK_TYPE_U8 }, - [IFLA_IPTUN_PMTUDISC] = { .type = NETLINK_TYPE_U8 }, - [IFLA_IPTUN_FLAGS] = { .type = NETLINK_TYPE_U16 }, - [IFLA_IPTUN_PROTO] = { .type = NETLINK_TYPE_U8 }, - [IFLA_IPTUN_6RD_PREFIX] = { .type = NETLINK_TYPE_IN_ADDR }, - [IFLA_IPTUN_6RD_RELAY_PREFIX] = { .type = NETLINK_TYPE_U32 }, - [IFLA_IPTUN_6RD_PREFIXLEN] = { .type = NETLINK_TYPE_U16 }, - [IFLA_IPTUN_6RD_RELAY_PREFIXLEN] = { .type = NETLINK_TYPE_U16 }, - [IFLA_IPTUN_ENCAP_TYPE] = { .type = NETLINK_TYPE_U16 }, - [IFLA_IPTUN_ENCAP_FLAGS] = { .type = NETLINK_TYPE_U16 }, - [IFLA_IPTUN_ENCAP_SPORT] = { .type = NETLINK_TYPE_U16 }, - [IFLA_IPTUN_ENCAP_DPORT] = { .type = NETLINK_TYPE_U16 }, -}; - -static const NLType rtnl_link_info_data_ipgre_types[] = { - [IFLA_GRE_LINK] = { .type = NETLINK_TYPE_U32 }, - [IFLA_GRE_IFLAGS] = { .type = NETLINK_TYPE_U16 }, - [IFLA_GRE_OFLAGS] = { .type = NETLINK_TYPE_U16 }, - [IFLA_GRE_IKEY] = { .type = NETLINK_TYPE_U32 }, - [IFLA_GRE_OKEY] = { .type = NETLINK_TYPE_U32 }, - [IFLA_GRE_LOCAL] = { .type = NETLINK_TYPE_IN_ADDR }, - [IFLA_GRE_REMOTE] = { .type = NETLINK_TYPE_IN_ADDR }, - [IFLA_GRE_TTL] = { .type = NETLINK_TYPE_U8 }, - [IFLA_GRE_TOS] = { .type = NETLINK_TYPE_U8 }, - [IFLA_GRE_PMTUDISC] = { .type = NETLINK_TYPE_U8 }, - [IFLA_GRE_FLOWINFO] = { .type = NETLINK_TYPE_U32 }, - [IFLA_GRE_FLAGS] = { .type = NETLINK_TYPE_U32 }, - [IFLA_GRE_ENCAP_TYPE] = { .type = NETLINK_TYPE_U16 }, - [IFLA_GRE_ENCAP_FLAGS] = { .type = NETLINK_TYPE_U16 }, - [IFLA_GRE_ENCAP_SPORT] = { .type = NETLINK_TYPE_U16 }, - [IFLA_GRE_ENCAP_DPORT] = { .type = NETLINK_TYPE_U16 }, - [IFLA_GRE_ERSPAN_INDEX] = { .type = NETLINK_TYPE_U32 }, -}; - -static const NLType rtnl_link_info_data_ipvti_types[] = { - [IFLA_VTI_LINK] = { .type = NETLINK_TYPE_U32 }, - [IFLA_VTI_IKEY] = { .type = NETLINK_TYPE_U32 }, - [IFLA_VTI_OKEY] = { .type = NETLINK_TYPE_U32 }, - [IFLA_VTI_LOCAL] = { .type = NETLINK_TYPE_IN_ADDR }, - [IFLA_VTI_REMOTE] = { .type = NETLINK_TYPE_IN_ADDR }, -}; - -static const NLType rtnl_link_info_data_ip6tnl_types[] = { - [IFLA_IPTUN_LINK] = { .type = NETLINK_TYPE_U32 }, - [IFLA_IPTUN_LOCAL] = { .type = NETLINK_TYPE_IN_ADDR }, - [IFLA_IPTUN_REMOTE] = { .type = NETLINK_TYPE_IN_ADDR }, - [IFLA_IPTUN_TTL] = { .type = NETLINK_TYPE_U8 }, - [IFLA_IPTUN_FLAGS] = { .type = NETLINK_TYPE_U32 }, - [IFLA_IPTUN_PROTO] = { .type = NETLINK_TYPE_U8 }, - [IFLA_IPTUN_ENCAP_LIMIT] = { .type = NETLINK_TYPE_U8 }, - [IFLA_IPTUN_FLOWINFO] = { .type = NETLINK_TYPE_U32 }, -}; - -static const NLType rtnl_link_info_data_vrf_types[] = { - [IFLA_VRF_TABLE] = { .type = NETLINK_TYPE_U32 }, -}; - -static const NLType rtnl_link_info_data_geneve_types[] = { - [IFLA_GENEVE_ID] = { .type = NETLINK_TYPE_U32 }, - [IFLA_GENEVE_TTL] = { .type = NETLINK_TYPE_U8 }, - [IFLA_GENEVE_TOS] = { .type = NETLINK_TYPE_U8 }, - [IFLA_GENEVE_PORT] = { .type = NETLINK_TYPE_U16 }, - [IFLA_GENEVE_REMOTE] = { .type = NETLINK_TYPE_IN_ADDR }, - [IFLA_GENEVE_REMOTE6] = { .type = NETLINK_TYPE_IN_ADDR }, - [IFLA_GENEVE_UDP_CSUM] = { .type = NETLINK_TYPE_U8 }, - [IFLA_GENEVE_UDP_ZERO_CSUM6_TX] = { .type = NETLINK_TYPE_U8 }, - [IFLA_GENEVE_UDP_ZERO_CSUM6_RX] = { .type = NETLINK_TYPE_U8 }, - [IFLA_GENEVE_LABEL] = { .type = NETLINK_TYPE_U32 }, - [IFLA_GENEVE_TTL_INHERIT] = { .type = NETLINK_TYPE_U8 }, - [IFLA_GENEVE_DF] = { .type = NETLINK_TYPE_U8 }, -}; - -static const NLType rtnl_link_info_data_can_types[] = { - [IFLA_CAN_BITTIMING] = { .size = sizeof(struct can_bittiming) }, - [IFLA_CAN_RESTART_MS] = { .type = NETLINK_TYPE_U32 }, - [IFLA_CAN_CTRLMODE] = { .size = sizeof(struct can_ctrlmode) }, - [IFLA_CAN_TERMINATION] = { .type = NETLINK_TYPE_U16 }, -}; - -static const NLType rtnl_link_info_data_macsec_types[] = { - [IFLA_MACSEC_SCI] = { .type = NETLINK_TYPE_U64 }, - [IFLA_MACSEC_PORT] = { .type = NETLINK_TYPE_U16 }, - [IFLA_MACSEC_ICV_LEN] = { .type = NETLINK_TYPE_U8 }, - [IFLA_MACSEC_CIPHER_SUITE] = { .type = NETLINK_TYPE_U64 }, - [IFLA_MACSEC_WINDOW] = { .type = NETLINK_TYPE_U32 }, - [IFLA_MACSEC_ENCODING_SA] = { .type = NETLINK_TYPE_U8 }, - [IFLA_MACSEC_ENCRYPT] = { .type = NETLINK_TYPE_U8 }, - [IFLA_MACSEC_PROTECT] = { .type = NETLINK_TYPE_U8 }, - [IFLA_MACSEC_INC_SCI] = { .type = NETLINK_TYPE_U8 }, - [IFLA_MACSEC_ES] = { .type = NETLINK_TYPE_U8 }, - [IFLA_MACSEC_SCB] = { .type = NETLINK_TYPE_U8 }, - [IFLA_MACSEC_REPLAY_PROTECT] = { .type = NETLINK_TYPE_U8 }, - [IFLA_MACSEC_VALIDATION] = { .type = NETLINK_TYPE_U8 }, -}; - -static const NLType rtnl_link_info_data_xfrm_types[] = { - [IFLA_XFRM_LINK] = { .type = NETLINK_TYPE_U32 }, - [IFLA_XFRM_IF_ID] = { .type = NETLINK_TYPE_U32 } -}; - -static const NLType rtnl_link_info_data_bareudp_types[] = { - [IFLA_BAREUDP_PORT] = { .type = NETLINK_TYPE_U16 }, - [IFLA_BAREUDP_ETHERTYPE] = { .type = NETLINK_TYPE_U16 }, - [IFLA_BAREUDP_SRCPORT_MIN] = { .type = NETLINK_TYPE_U16 }, - [IFLA_BAREUDP_MULTIPROTO_MODE] = { .type = NETLINK_TYPE_FLAG }, -}; - -/* these strings must match the .kind entries in the kernel */ -static const char* const nl_union_link_info_data_table[] = { - [NL_UNION_LINK_INFO_DATA_BOND] = "bond", - [NL_UNION_LINK_INFO_DATA_BRIDGE] = "bridge", - [NL_UNION_LINK_INFO_DATA_VLAN] = "vlan", - [NL_UNION_LINK_INFO_DATA_VETH] = "veth", - [NL_UNION_LINK_INFO_DATA_DUMMY] = "dummy", - [NL_UNION_LINK_INFO_DATA_MACVLAN] = "macvlan", - [NL_UNION_LINK_INFO_DATA_MACVTAP] = "macvtap", - [NL_UNION_LINK_INFO_DATA_IPVLAN] = "ipvlan", - [NL_UNION_LINK_INFO_DATA_IPVTAP] = "ipvtap", - [NL_UNION_LINK_INFO_DATA_VXLAN] = "vxlan", - [NL_UNION_LINK_INFO_DATA_IPIP_TUNNEL] = "ipip", - [NL_UNION_LINK_INFO_DATA_IPGRE_TUNNEL] = "gre", - [NL_UNION_LINK_INFO_DATA_ERSPAN] = "erspan", - [NL_UNION_LINK_INFO_DATA_IPGRETAP_TUNNEL] = "gretap", - [NL_UNION_LINK_INFO_DATA_IP6GRE_TUNNEL] = "ip6gre", - [NL_UNION_LINK_INFO_DATA_IP6GRETAP_TUNNEL] = "ip6gretap", - [NL_UNION_LINK_INFO_DATA_SIT_TUNNEL] = "sit", - [NL_UNION_LINK_INFO_DATA_VTI_TUNNEL] = "vti", - [NL_UNION_LINK_INFO_DATA_VTI6_TUNNEL] = "vti6", - [NL_UNION_LINK_INFO_DATA_IP6TNL_TUNNEL] = "ip6tnl", - [NL_UNION_LINK_INFO_DATA_VRF] = "vrf", - [NL_UNION_LINK_INFO_DATA_VCAN] = "vcan", - [NL_UNION_LINK_INFO_DATA_GENEVE] = "geneve", - [NL_UNION_LINK_INFO_DATA_VXCAN] = "vxcan", - [NL_UNION_LINK_INFO_DATA_WIREGUARD] = "wireguard", - [NL_UNION_LINK_INFO_DATA_NETDEVSIM] = "netdevsim", - [NL_UNION_LINK_INFO_DATA_CAN] = "can", - [NL_UNION_LINK_INFO_DATA_MACSEC] = "macsec", - [NL_UNION_LINK_INFO_DATA_NLMON] = "nlmon", - [NL_UNION_LINK_INFO_DATA_XFRM] = "xfrm", - [NL_UNION_LINK_INFO_DATA_IFB] = "ifb", - [NL_UNION_LINK_INFO_DATA_BAREUDP] = "bareudp", - [NL_UNION_LINK_INFO_DATA_BATADV] = "batadv", -}; - -DEFINE_STRING_TABLE_LOOKUP(nl_union_link_info_data, NLUnionLinkInfoData); - -static const NLTypeSystem rtnl_link_info_data_type_systems[] = { - [NL_UNION_LINK_INFO_DATA_BOND] = { .count = ELEMENTSOF(rtnl_link_info_data_bond_types), - .types = rtnl_link_info_data_bond_types }, - [NL_UNION_LINK_INFO_DATA_BRIDGE] = { .count = ELEMENTSOF(rtnl_link_info_data_bridge_types), - .types = rtnl_link_info_data_bridge_types }, - [NL_UNION_LINK_INFO_DATA_VLAN] = { .count = ELEMENTSOF(rtnl_link_info_data_vlan_types), - .types = rtnl_link_info_data_vlan_types }, - [NL_UNION_LINK_INFO_DATA_VETH] = { .count = ELEMENTSOF(rtnl_link_info_data_veth_types), - .types = rtnl_link_info_data_veth_types }, - [NL_UNION_LINK_INFO_DATA_MACVLAN] = { .count = ELEMENTSOF(rtnl_link_info_data_macvlan_types), - .types = rtnl_link_info_data_macvlan_types }, - [NL_UNION_LINK_INFO_DATA_MACVTAP] = { .count = ELEMENTSOF(rtnl_link_info_data_macvlan_types), - .types = rtnl_link_info_data_macvlan_types }, - [NL_UNION_LINK_INFO_DATA_IPVLAN] = { .count = ELEMENTSOF(rtnl_link_info_data_ipvlan_types), - .types = rtnl_link_info_data_ipvlan_types }, - [NL_UNION_LINK_INFO_DATA_IPVTAP] = { .count = ELEMENTSOF(rtnl_link_info_data_ipvlan_types), - .types = rtnl_link_info_data_ipvlan_types }, - [NL_UNION_LINK_INFO_DATA_VXLAN] = { .count = ELEMENTSOF(rtnl_link_info_data_vxlan_types), - .types = rtnl_link_info_data_vxlan_types }, - [NL_UNION_LINK_INFO_DATA_IPIP_TUNNEL] = { .count = ELEMENTSOF(rtnl_link_info_data_iptun_types), - .types = rtnl_link_info_data_iptun_types }, - [NL_UNION_LINK_INFO_DATA_IPGRE_TUNNEL] = { .count = ELEMENTSOF(rtnl_link_info_data_ipgre_types), - .types = rtnl_link_info_data_ipgre_types }, - [NL_UNION_LINK_INFO_DATA_ERSPAN] = { .count = ELEMENTSOF(rtnl_link_info_data_ipgre_types), - .types = rtnl_link_info_data_ipgre_types }, - [NL_UNION_LINK_INFO_DATA_IPGRETAP_TUNNEL] = { .count = ELEMENTSOF(rtnl_link_info_data_ipgre_types), - .types = rtnl_link_info_data_ipgre_types }, - [NL_UNION_LINK_INFO_DATA_IP6GRE_TUNNEL] = { .count = ELEMENTSOF(rtnl_link_info_data_ipgre_types), - .types = rtnl_link_info_data_ipgre_types }, - [NL_UNION_LINK_INFO_DATA_IP6GRETAP_TUNNEL] = { .count = ELEMENTSOF(rtnl_link_info_data_ipgre_types), - .types = rtnl_link_info_data_ipgre_types }, - [NL_UNION_LINK_INFO_DATA_SIT_TUNNEL] = { .count = ELEMENTSOF(rtnl_link_info_data_iptun_types), - .types = rtnl_link_info_data_iptun_types }, - [NL_UNION_LINK_INFO_DATA_VTI_TUNNEL] = { .count = ELEMENTSOF(rtnl_link_info_data_ipvti_types), - .types = rtnl_link_info_data_ipvti_types }, - [NL_UNION_LINK_INFO_DATA_VTI6_TUNNEL] = { .count = ELEMENTSOF(rtnl_link_info_data_ipvti_types), - .types = rtnl_link_info_data_ipvti_types }, - [NL_UNION_LINK_INFO_DATA_IP6TNL_TUNNEL] = { .count = ELEMENTSOF(rtnl_link_info_data_ip6tnl_types), - .types = rtnl_link_info_data_ip6tnl_types }, - [NL_UNION_LINK_INFO_DATA_VRF] = { .count = ELEMENTSOF(rtnl_link_info_data_vrf_types), - .types = rtnl_link_info_data_vrf_types }, - [NL_UNION_LINK_INFO_DATA_GENEVE] = { .count = ELEMENTSOF(rtnl_link_info_data_geneve_types), - .types = rtnl_link_info_data_geneve_types }, - [NL_UNION_LINK_INFO_DATA_VXCAN] = { .count = ELEMENTSOF(rtnl_link_info_data_vxcan_types), - .types = rtnl_link_info_data_vxcan_types }, - [NL_UNION_LINK_INFO_DATA_CAN] = { .count = ELEMENTSOF(rtnl_link_info_data_can_types), - .types = rtnl_link_info_data_can_types }, - [NL_UNION_LINK_INFO_DATA_MACSEC] = { .count = ELEMENTSOF(rtnl_link_info_data_macsec_types), - .types = rtnl_link_info_data_macsec_types }, - [NL_UNION_LINK_INFO_DATA_XFRM] = { .count = ELEMENTSOF(rtnl_link_info_data_xfrm_types), - .types = rtnl_link_info_data_xfrm_types }, - [NL_UNION_LINK_INFO_DATA_BAREUDP] = { .count = ELEMENTSOF(rtnl_link_info_data_bareudp_types), - .types = rtnl_link_info_data_bareudp_types }, - [NL_UNION_LINK_INFO_DATA_BATADV] = { .count = ELEMENTSOF(rtnl_link_info_data_batadv_types), - .types = rtnl_link_info_data_batadv_types }, -}; - -static const NLTypeSystemUnion rtnl_link_info_data_type_system_union = { - .num = _NL_UNION_LINK_INFO_DATA_MAX, - .lookup = nl_union_link_info_data_from_string, - .type_systems = rtnl_link_info_data_type_systems, - .match_type = NL_MATCH_SIBLING, - .match = IFLA_INFO_KIND, -}; - -static const NLType rtnl_link_info_types[] = { - [IFLA_INFO_KIND] = { .type = NETLINK_TYPE_STRING }, - [IFLA_INFO_DATA] = { .type = NETLINK_TYPE_UNION, .type_system_union = &rtnl_link_info_data_type_system_union }, -/* - [IFLA_INFO_XSTATS], - [IFLA_INFO_SLAVE_KIND] = { .type = NETLINK_TYPE_STRING }, - [IFLA_INFO_SLAVE_DATA] = { .type = NETLINK_TYPE_NESTED }, -*/ -}; - -static const NLTypeSystem rtnl_link_info_type_system = { - .count = ELEMENTSOF(rtnl_link_info_types), - .types = rtnl_link_info_types, -}; - -static const struct NLType rtnl_prot_info_bridge_port_types[] = { - [IFLA_BRPORT_STATE] = { .type = NETLINK_TYPE_U8 }, - [IFLA_BRPORT_COST] = { .type = NETLINK_TYPE_U32 }, - [IFLA_BRPORT_PRIORITY] = { .type = NETLINK_TYPE_U16 }, - [IFLA_BRPORT_MODE] = { .type = NETLINK_TYPE_U8 }, - [IFLA_BRPORT_GUARD] = { .type = NETLINK_TYPE_U8 }, - [IFLA_BRPORT_PROTECT] = { .type = NETLINK_TYPE_U8 }, - [IFLA_BRPORT_FAST_LEAVE] = { .type = NETLINK_TYPE_U8 }, - [IFLA_BRPORT_LEARNING] = { .type = NETLINK_TYPE_U8 }, - [IFLA_BRPORT_UNICAST_FLOOD] = { .type = NETLINK_TYPE_U8 }, - [IFLA_BRPORT_PROXYARP] = { .type = NETLINK_TYPE_U8 }, - [IFLA_BRPORT_LEARNING_SYNC] = { .type = NETLINK_TYPE_U8 }, - [IFLA_BRPORT_PROXYARP_WIFI] = { .type = NETLINK_TYPE_U8 }, - [IFLA_BRPORT_ROOT_ID] = { .type = NETLINK_TYPE_U8 }, - [IFLA_BRPORT_BRIDGE_ID] = { .type = NETLINK_TYPE_U8 }, - [IFLA_BRPORT_DESIGNATED_PORT] = { .type = NETLINK_TYPE_U16 }, - [IFLA_BRPORT_DESIGNATED_COST] = { .type = NETLINK_TYPE_U16 }, - [IFLA_BRPORT_ID] = { .type = NETLINK_TYPE_U16 }, - [IFLA_BRPORT_NO] = { .type = NETLINK_TYPE_U16 }, - [IFLA_BRPORT_TOPOLOGY_CHANGE_ACK] = { .type = NETLINK_TYPE_U8 }, - [IFLA_BRPORT_CONFIG_PENDING] = { .type = NETLINK_TYPE_U8 }, - [IFLA_BRPORT_MESSAGE_AGE_TIMER] = { .type = NETLINK_TYPE_U64 }, - [IFLA_BRPORT_FORWARD_DELAY_TIMER] = { .type = NETLINK_TYPE_U64 }, - [IFLA_BRPORT_HOLD_TIMER] = { .type = NETLINK_TYPE_U64 }, - [IFLA_BRPORT_FLUSH] = { .type = NETLINK_TYPE_U8 }, - [IFLA_BRPORT_MULTICAST_ROUTER] = { .type = NETLINK_TYPE_U8 }, - [IFLA_BRPORT_PAD] = { .type = NETLINK_TYPE_U8 }, - [IFLA_BRPORT_MCAST_FLOOD] = { .type = NETLINK_TYPE_U8 }, - [IFLA_BRPORT_MCAST_TO_UCAST] = { .type = NETLINK_TYPE_U8 }, - [IFLA_BRPORT_VLAN_TUNNEL] = { .type = NETLINK_TYPE_U8 }, - [IFLA_BRPORT_BCAST_FLOOD] = { .type = NETLINK_TYPE_U8 }, - [IFLA_BRPORT_GROUP_FWD_MASK] = { .type = NETLINK_TYPE_U16 }, - [IFLA_BRPORT_NEIGH_SUPPRESS] = { .type = NETLINK_TYPE_U8 }, - [IFLA_BRPORT_ISOLATED] = { .type = NETLINK_TYPE_U8 }, - [IFLA_BRPORT_BACKUP_PORT] = { .type = NETLINK_TYPE_U32 }, -}; - -static const NLTypeSystem rtnl_prot_info_type_systems[] = { - [AF_BRIDGE] = { .count = ELEMENTSOF(rtnl_prot_info_bridge_port_types), - .types = rtnl_prot_info_bridge_port_types }, -}; - -static const NLTypeSystemUnion rtnl_prot_info_type_system_union = { - .num = AF_MAX, - .type_systems = rtnl_prot_info_type_systems, - .match_type = NL_MATCH_PROTOCOL, -}; - -static const struct NLType rtnl_af_spec_inet6_types[] = { - [IFLA_INET6_FLAGS] = { .type = NETLINK_TYPE_U32 }, -/* - IFLA_INET6_CONF, - IFLA_INET6_STATS, - IFLA_INET6_MCAST, - IFLA_INET6_CACHEINFO, - IFLA_INET6_ICMP6STATS, -*/ - [IFLA_INET6_TOKEN] = { .type = NETLINK_TYPE_IN_ADDR }, - [IFLA_INET6_ADDR_GEN_MODE] = { .type = NETLINK_TYPE_U8 }, -}; - -static const NLTypeSystem rtnl_af_spec_inet6_type_system = { - .count = ELEMENTSOF(rtnl_af_spec_inet6_types), - .types = rtnl_af_spec_inet6_types, -}; - -static const NLType rtnl_af_spec_unspec_types[] = { - [AF_INET6] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_af_spec_inet6_type_system }, -}; - -static const NLType rtnl_af_spec_bridge_types[] = { - [IFLA_BRIDGE_FLAGS] = { .type = NETLINK_TYPE_U16 }, - [IFLA_BRIDGE_VLAN_INFO] = { .size = sizeof(struct bridge_vlan_info) }, -}; - -static const NLTypeSystem rtnl_af_spec_type_systems[] = { - [AF_UNSPEC] = { .count = ELEMENTSOF(rtnl_af_spec_unspec_types), - .types = rtnl_af_spec_unspec_types }, - [AF_BRIDGE] = { .count = ELEMENTSOF(rtnl_af_spec_bridge_types), - .types = rtnl_af_spec_bridge_types }, -}; - -static const NLTypeSystemUnion rtnl_af_spec_type_system_union = { - .num = AF_MAX, - .type_systems = rtnl_af_spec_type_systems, - .match_type = NL_MATCH_PROTOCOL, -}; - -static const NLType rtnl_prop_list_types[] = { - [IFLA_ALT_IFNAME] = { .type = NETLINK_TYPE_STRING, .size = ALTIFNAMSIZ - 1 }, -}; - -static const NLTypeSystem rtnl_prop_list_type_system = { - .count = ELEMENTSOF(rtnl_prop_list_types), - .types = rtnl_prop_list_types, -}; - -static const NLType rtnl_vf_vlan_list_types[] = { - [IFLA_VF_VLAN_INFO] = { .size = sizeof(struct ifla_vf_vlan_info) }, -}; - -static const NLTypeSystem rtnl_vf_vlan_type_system = { - .count = ELEMENTSOF(rtnl_vf_vlan_list_types), - .types = rtnl_vf_vlan_list_types, -}; - -static const NLType rtnl_vf_vlan_info_types[] = { - [IFLA_VF_MAC] = { .size = sizeof(struct ifla_vf_mac) }, - [IFLA_VF_VLAN] = { .size = sizeof(struct ifla_vf_vlan) }, - [IFLA_VF_VLAN_LIST] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_vf_vlan_type_system}, - [IFLA_VF_TX_RATE] = { .size = sizeof(struct ifla_vf_tx_rate) }, - [IFLA_VF_SPOOFCHK] = { .size = sizeof(struct ifla_vf_spoofchk) }, - [IFLA_VF_RATE] = { .size = sizeof(struct ifla_vf_rate) }, - [IFLA_VF_LINK_STATE] = { .size = sizeof(struct ifla_vf_link_state) }, - [IFLA_VF_RSS_QUERY_EN] = { .size = sizeof(struct ifla_vf_rss_query_en) }, - [IFLA_VF_TRUST] = { .size = sizeof(struct ifla_vf_trust) }, - [IFLA_VF_IB_NODE_GUID] = { .size = sizeof(struct ifla_vf_guid) }, - [IFLA_VF_IB_PORT_GUID] = { .size = sizeof(struct ifla_vf_guid) }, -}; - -static const NLTypeSystem rtnl_vf_vlan_info_type_system = { - .count = ELEMENTSOF(rtnl_vf_vlan_info_types), - .types = rtnl_vf_vlan_info_types, -}; - -static const NLType rtnl_link_io_srv_types[] = { - [IFLA_VF_INFO] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_vf_vlan_info_type_system }, -}; - -static const NLTypeSystem rtnl_io_srv_type_system = { - .count = ELEMENTSOF(rtnl_link_io_srv_types), - .types = rtnl_link_io_srv_types, -}; - -static const NLType rtnl_link_types[] = { - [IFLA_ADDRESS] = { .type = NETLINK_TYPE_ETHER_ADDR }, - [IFLA_BROADCAST] = { .type = NETLINK_TYPE_ETHER_ADDR }, - [IFLA_IFNAME] = { .type = NETLINK_TYPE_STRING, .size = IFNAMSIZ - 1 }, - [IFLA_MTU] = { .type = NETLINK_TYPE_U32 }, - [IFLA_LINK] = { .type = NETLINK_TYPE_U32 }, - [IFLA_QDISC] = { .type = NETLINK_TYPE_STRING }, - [IFLA_STATS] = { .size = sizeof(struct rtnl_link_stats) }, -/* - [IFLA_COST], - [IFLA_PRIORITY], -*/ - [IFLA_MASTER] = { .type = NETLINK_TYPE_U32 }, -/* - [IFLA_WIRELESS], -*/ - [IFLA_PROTINFO] = { .type = NETLINK_TYPE_UNION, .type_system_union = &rtnl_prot_info_type_system_union }, - [IFLA_TXQLEN] = { .type = NETLINK_TYPE_U32 }, -/* - [IFLA_MAP] = { .len = sizeof(struct rtnl_link_ifmap) }, -*/ - [IFLA_WEIGHT] = { .type = NETLINK_TYPE_U32 }, - [IFLA_OPERSTATE] = { .type = NETLINK_TYPE_U8 }, - [IFLA_LINKMODE] = { .type = NETLINK_TYPE_U8 }, - [IFLA_LINKINFO] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_link_info_type_system }, - [IFLA_NET_NS_PID] = { .type = NETLINK_TYPE_U32 }, - [IFLA_IFALIAS] = { .type = NETLINK_TYPE_STRING, .size = IFALIASZ - 1 }, - [IFLA_NUM_VF] = { .type = NETLINK_TYPE_U32 }, - [IFLA_VFINFO_LIST] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_io_srv_type_system }, - [IFLA_STATS64] = { .size = sizeof(struct rtnl_link_stats64) }, -/* - [IFLA_VF_PORTS] = { .type = NETLINK_TYPE_NESTED }, - [IFLA_PORT_SELF] = { .type = NETLINK_TYPE_NESTED }, -*/ - [IFLA_AF_SPEC] = { .type = NETLINK_TYPE_UNION, .type_system_union = &rtnl_af_spec_type_system_union }, -/* - [IFLA_VF_PORTS], - [IFLA_PORT_SELF], -*/ - [IFLA_GROUP] = { .type = NETLINK_TYPE_U32 }, - [IFLA_NET_NS_FD] = { .type = NETLINK_TYPE_U32 }, - [IFLA_EXT_MASK] = { .type = NETLINK_TYPE_U32 }, - [IFLA_PROMISCUITY] = { .type = NETLINK_TYPE_U32 }, - [IFLA_NUM_TX_QUEUES] = { .type = NETLINK_TYPE_U32 }, - [IFLA_NUM_RX_QUEUES] = { .type = NETLINK_TYPE_U32 }, - [IFLA_GSO_MAX_SEGS] = { .type = NETLINK_TYPE_U32 }, - [IFLA_GSO_MAX_SIZE] = { .type = NETLINK_TYPE_U32 }, - [IFLA_CARRIER] = { .type = NETLINK_TYPE_U8 }, -/* - [IFLA_PHYS_PORT_ID] = { .type = NETLINK_TYPE_BINARY, .len = MAX_PHYS_PORT_ID_LEN }, -*/ - [IFLA_MIN_MTU] = { .type = NETLINK_TYPE_U32 }, - [IFLA_MAX_MTU] = { .type = NETLINK_TYPE_U32 }, - [IFLA_PROP_LIST] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_prop_list_type_system }, - [IFLA_ALT_IFNAME] = { .type = NETLINK_TYPE_STRING, .size = ALTIFNAMSIZ - 1 }, -}; - -static const NLTypeSystem rtnl_link_type_system = { - .count = ELEMENTSOF(rtnl_link_types), - .types = rtnl_link_types, -}; - -/* IFA_FLAGS was defined in kernel 3.14, but we still support older - * kernels where IFA_MAX is lower. */ -static const NLType rtnl_address_types[] = { - [IFA_ADDRESS] = { .type = NETLINK_TYPE_IN_ADDR }, - [IFA_LOCAL] = { .type = NETLINK_TYPE_IN_ADDR }, - [IFA_LABEL] = { .type = NETLINK_TYPE_STRING, .size = IFNAMSIZ - 1 }, - [IFA_BROADCAST] = { .type = NETLINK_TYPE_IN_ADDR }, - [IFA_ANYCAST] = { .type = NETLINK_TYPE_IN_ADDR }, - [IFA_CACHEINFO] = { .type = NETLINK_TYPE_CACHE_INFO, .size = sizeof(struct ifa_cacheinfo) }, - [IFA_MULTICAST] = { .type = NETLINK_TYPE_IN_ADDR }, - [IFA_FLAGS] = { .type = NETLINK_TYPE_U32 }, - [IFA_RT_PRIORITY] = { .type = NETLINK_TYPE_U32 }, - [IFA_TARGET_NETNSID] = { .type = NETLINK_TYPE_S32 }, -}; - -static const NLTypeSystem rtnl_address_type_system = { - .count = ELEMENTSOF(rtnl_address_types), - .types = rtnl_address_types, -}; - -/* RTM_METRICS --- array of struct rtattr with types of RTAX_* */ - -static const NLType rtnl_route_metrics_types[] = { - [RTAX_MTU] = { .type = NETLINK_TYPE_U32 }, - [RTAX_WINDOW] = { .type = NETLINK_TYPE_U32 }, - [RTAX_RTT] = { .type = NETLINK_TYPE_U32 }, - [RTAX_RTTVAR] = { .type = NETLINK_TYPE_U32 }, - [RTAX_SSTHRESH] = { .type = NETLINK_TYPE_U32 }, - [RTAX_CWND] = { .type = NETLINK_TYPE_U32 }, - [RTAX_ADVMSS] = { .type = NETLINK_TYPE_U32 }, - [RTAX_REORDERING] = { .type = NETLINK_TYPE_U32 }, - [RTAX_HOPLIMIT] = { .type = NETLINK_TYPE_U32 }, - [RTAX_INITCWND] = { .type = NETLINK_TYPE_U32 }, - [RTAX_FEATURES] = { .type = NETLINK_TYPE_U32 }, - [RTAX_RTO_MIN] = { .type = NETLINK_TYPE_U32 }, - [RTAX_INITRWND] = { .type = NETLINK_TYPE_U32 }, - [RTAX_QUICKACK] = { .type = NETLINK_TYPE_U32 }, - [RTAX_CC_ALGO] = { .type = NETLINK_TYPE_U32 }, - [RTAX_FASTOPEN_NO_COOKIE] = { .type = NETLINK_TYPE_U32 }, -}; - -static const NLTypeSystem rtnl_route_metrics_type_system = { - .count = ELEMENTSOF(rtnl_route_metrics_types), - .types = rtnl_route_metrics_types, -}; - -static const NLType rtnl_route_types[] = { - [RTA_DST] = { .type = NETLINK_TYPE_IN_ADDR }, /* 6? */ - [RTA_SRC] = { .type = NETLINK_TYPE_IN_ADDR }, /* 6? */ - [RTA_IIF] = { .type = NETLINK_TYPE_U32 }, - [RTA_OIF] = { .type = NETLINK_TYPE_U32 }, - [RTA_GATEWAY] = { .type = NETLINK_TYPE_IN_ADDR }, - [RTA_PRIORITY] = { .type = NETLINK_TYPE_U32 }, - [RTA_PREFSRC] = { .type = NETLINK_TYPE_IN_ADDR }, /* 6? */ - [RTA_METRICS] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_route_metrics_type_system}, - [RTA_MULTIPATH] = { .size = sizeof(struct rtnexthop) }, - [RTA_FLOW] = { .type = NETLINK_TYPE_U32 }, /* 6? */ - [RTA_CACHEINFO] = { .size = sizeof(struct rta_cacheinfo) }, - [RTA_TABLE] = { .type = NETLINK_TYPE_U32 }, - [RTA_MARK] = { .type = NETLINK_TYPE_U32 }, - [RTA_MFC_STATS] = { .type = NETLINK_TYPE_U64 }, - [RTA_VIA] = { /* See struct rtvia */ }, - [RTA_NEWDST] = { .type = NETLINK_TYPE_U32 }, - [RTA_PREF] = { .type = NETLINK_TYPE_U8 }, - [RTA_ENCAP_TYPE] = { .type = NETLINK_TYPE_U16 }, - [RTA_ENCAP] = { .type = NETLINK_TYPE_NESTED }, /* Multiple type systems i.e. LWTUNNEL_ENCAP_MPLS/LWTUNNEL_ENCAP_IP/LWTUNNEL_ENCAP_ILA etc... */ - [RTA_EXPIRES] = { .type = NETLINK_TYPE_U32 }, - [RTA_UID] = { .type = NETLINK_TYPE_U32 }, - [RTA_TTL_PROPAGATE] = { .type = NETLINK_TYPE_U8 }, - [RTA_IP_PROTO] = { .type = NETLINK_TYPE_U8 }, - [RTA_SPORT] = { .type = NETLINK_TYPE_U16 }, - [RTA_DPORT] = { .type = NETLINK_TYPE_U16 }, - [RTA_NH_ID] = { .type = NETLINK_TYPE_U32 }, -}; - -static const NLTypeSystem rtnl_route_type_system = { - .count = ELEMENTSOF(rtnl_route_types), - .types = rtnl_route_types, -}; - -static const NLType rtnl_neigh_types[] = { - [NDA_DST] = { .type = NETLINK_TYPE_IN_ADDR }, - [NDA_LLADDR] = { /* struct ether_addr, struct in_addr, or struct in6_addr */ }, - [NDA_CACHEINFO] = { .type = NETLINK_TYPE_CACHE_INFO, .size = sizeof(struct nda_cacheinfo) }, - [NDA_PROBES] = { .type = NETLINK_TYPE_U32 }, - [NDA_VLAN] = { .type = NETLINK_TYPE_U16 }, - [NDA_PORT] = { .type = NETLINK_TYPE_U16 }, - [NDA_VNI] = { .type = NETLINK_TYPE_U32 }, - [NDA_IFINDEX] = { .type = NETLINK_TYPE_U32 }, -}; - -static const NLTypeSystem rtnl_neigh_type_system = { - .count = ELEMENTSOF(rtnl_neigh_types), - .types = rtnl_neigh_types, -}; - -static const NLType rtnl_addrlabel_types[] = { - [IFAL_ADDRESS] = { .type = NETLINK_TYPE_IN_ADDR, .size = sizeof(struct in6_addr) }, - [IFAL_LABEL] = { .type = NETLINK_TYPE_U32 }, -}; - -static const NLTypeSystem rtnl_addrlabel_type_system = { - .count = ELEMENTSOF(rtnl_addrlabel_types), - .types = rtnl_addrlabel_types, -}; - -static const NLType rtnl_routing_policy_rule_types[] = { - [FRA_DST] = { .type = NETLINK_TYPE_IN_ADDR }, - [FRA_SRC] = { .type = NETLINK_TYPE_IN_ADDR }, - [FRA_IIFNAME] = { .type = NETLINK_TYPE_STRING }, - [FRA_GOTO] = { .type = NETLINK_TYPE_U32 }, - [FRA_PRIORITY] = { .type = NETLINK_TYPE_U32 }, - [FRA_FWMARK] = { .type = NETLINK_TYPE_U32 }, - [FRA_FLOW] = { .type = NETLINK_TYPE_U32 }, - [FRA_TUN_ID] = { .type = NETLINK_TYPE_U64 }, - [FRA_SUPPRESS_IFGROUP] = { .type = NETLINK_TYPE_U32 }, - [FRA_SUPPRESS_PREFIXLEN] = { .type = NETLINK_TYPE_U32 }, - [FRA_TABLE] = { .type = NETLINK_TYPE_U32 }, - [FRA_FWMASK] = { .type = NETLINK_TYPE_U32 }, - [FRA_OIFNAME] = { .type = NETLINK_TYPE_STRING }, - [FRA_PAD] = { .type = NETLINK_TYPE_U32 }, - [FRA_L3MDEV] = { .type = NETLINK_TYPE_U8 }, - [FRA_UID_RANGE] = { .size = sizeof(struct fib_rule_uid_range) }, - [FRA_PROTOCOL] = { .type = NETLINK_TYPE_U8 }, - [FRA_IP_PROTO] = { .type = NETLINK_TYPE_U8 }, - [FRA_SPORT_RANGE] = { .size = sizeof(struct fib_rule_port_range) }, - [FRA_DPORT_RANGE] = { .size = sizeof(struct fib_rule_port_range) }, -}; - -static const NLTypeSystem rtnl_routing_policy_rule_type_system = { - .count = ELEMENTSOF(rtnl_routing_policy_rule_types), - .types = rtnl_routing_policy_rule_types, -}; - -static const NLType rtnl_nexthop_types[] = { - [NHA_ID] = { .type = NETLINK_TYPE_U32 }, - [NHA_GROUP] = { /* array of struct nexthop_grp */ }, - [NHA_GROUP_TYPE] = { .type = NETLINK_TYPE_U16 }, - [NHA_BLACKHOLE] = { .type = NETLINK_TYPE_FLAG }, - [NHA_OIF] = { .type = NETLINK_TYPE_U32 }, - [NHA_GATEWAY] = { .type = NETLINK_TYPE_IN_ADDR }, - [NHA_ENCAP_TYPE] = { .type = NETLINK_TYPE_U16 }, - [NHA_ENCAP] = { .type = NETLINK_TYPE_NESTED }, - [NHA_GROUPS] = { .type = NETLINK_TYPE_FLAG }, - [NHA_MASTER] = { .type = NETLINK_TYPE_U32 }, - [NHA_FDB] = { .type = NETLINK_TYPE_FLAG }, -}; - -static const NLTypeSystem rtnl_nexthop_type_system = { - .count = ELEMENTSOF(rtnl_nexthop_types), - .types = rtnl_nexthop_types, -}; - -static const NLType rtnl_tca_option_data_cake_types[] = { - [TCA_CAKE_BASE_RATE64] = { .type = NETLINK_TYPE_U64 }, - [TCA_CAKE_OVERHEAD] = { .type = NETLINK_TYPE_S32 }, - [TCA_CAKE_MPU] = { .type = NETLINK_TYPE_U32 }, -}; - -static const NLType rtnl_tca_option_data_codel_types[] = { - [TCA_CODEL_TARGET] = { .type = NETLINK_TYPE_U32 }, - [TCA_CODEL_LIMIT] = { .type = NETLINK_TYPE_U32 }, - [TCA_CODEL_INTERVAL] = { .type = NETLINK_TYPE_U32 }, - [TCA_CODEL_ECN] = { .type = NETLINK_TYPE_U32 }, - [TCA_CODEL_CE_THRESHOLD] = { .type = NETLINK_TYPE_U32 }, -}; - -static const NLType rtnl_tca_option_data_drr_types[] = { - [TCA_DRR_QUANTUM] = { .type = NETLINK_TYPE_U32 }, -}; - -static const NLType rtnl_tca_option_data_ets_quanta_types[] = { - [TCA_ETS_QUANTA_BAND] = { .type = NETLINK_TYPE_U32, }, -}; - -static const NLTypeSystem rtnl_tca_option_data_ets_quanta_type_system = { - .count = ELEMENTSOF(rtnl_tca_option_data_ets_quanta_types), - .types = rtnl_tca_option_data_ets_quanta_types, -}; - -static const NLType rtnl_tca_option_data_ets_prio_types[] = { - [TCA_ETS_PRIOMAP_BAND] = { .type = NETLINK_TYPE_U8, }, -}; - -static const NLTypeSystem rtnl_tca_option_data_ets_prio_type_system = { - .count = ELEMENTSOF(rtnl_tca_option_data_ets_prio_types), - .types = rtnl_tca_option_data_ets_prio_types, -}; - -static const NLType rtnl_tca_option_data_ets_types[] = { - [TCA_ETS_NBANDS] = { .type = NETLINK_TYPE_U8 }, - [TCA_ETS_NSTRICT] = { .type = NETLINK_TYPE_U8 }, - [TCA_ETS_QUANTA] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_tca_option_data_ets_quanta_type_system }, - [TCA_ETS_PRIOMAP] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_tca_option_data_ets_prio_type_system }, - [TCA_ETS_QUANTA_BAND] = { .type = NETLINK_TYPE_U32 }, -}; - -static const NLType rtnl_tca_option_data_fq_types[] = { - [TCA_FQ_PLIMIT] = { .type = NETLINK_TYPE_U32 }, - [TCA_FQ_FLOW_PLIMIT] = { .type = NETLINK_TYPE_U32 }, - [TCA_FQ_QUANTUM] = { .type = NETLINK_TYPE_U32 }, - [TCA_FQ_INITIAL_QUANTUM] = { .type = NETLINK_TYPE_U32 }, - [TCA_FQ_RATE_ENABLE] = { .type = NETLINK_TYPE_U32 }, - [TCA_FQ_FLOW_DEFAULT_RATE] = { .type = NETLINK_TYPE_U32 }, - [TCA_FQ_FLOW_MAX_RATE] = { .type = NETLINK_TYPE_U32 }, - [TCA_FQ_BUCKETS_LOG] = { .type = NETLINK_TYPE_U32 }, - [TCA_FQ_FLOW_REFILL_DELAY] = { .type = NETLINK_TYPE_U32 }, - [TCA_FQ_LOW_RATE_THRESHOLD] = { .type = NETLINK_TYPE_U32 }, - [TCA_FQ_CE_THRESHOLD] = { .type = NETLINK_TYPE_U32 }, - [TCA_FQ_ORPHAN_MASK] = { .type = NETLINK_TYPE_U32 }, -}; - -static const NLType rtnl_tca_option_data_fq_codel_types[] = { - [TCA_FQ_CODEL_TARGET] = { .type = NETLINK_TYPE_U32 }, - [TCA_FQ_CODEL_LIMIT] = { .type = NETLINK_TYPE_U32 }, - [TCA_FQ_CODEL_INTERVAL] = { .type = NETLINK_TYPE_U32 }, - [TCA_FQ_CODEL_ECN] = { .type = NETLINK_TYPE_U32 }, - [TCA_FQ_CODEL_FLOWS] = { .type = NETLINK_TYPE_U32 }, - [TCA_FQ_CODEL_QUANTUM] = { .type = NETLINK_TYPE_U32 }, - [TCA_FQ_CODEL_CE_THRESHOLD] = { .type = NETLINK_TYPE_U32 }, - [TCA_FQ_CODEL_DROP_BATCH_SIZE] = { .type = NETLINK_TYPE_U32 }, - [TCA_FQ_CODEL_MEMORY_LIMIT] = { .type = NETLINK_TYPE_U32 }, -}; - -static const NLType rtnl_tca_option_data_fq_pie_types[] = { - [TCA_FQ_PIE_LIMIT] = { .type = NETLINK_TYPE_U32 }, -}; - -static const NLType rtnl_tca_option_data_gred_types[] = { - [TCA_GRED_DPS] = { .size = sizeof(struct tc_gred_sopt) }, -}; - -static const NLType rtnl_tca_option_data_hhf_types[] = { - [TCA_HHF_BACKLOG_LIMIT] = { .type = NETLINK_TYPE_U32 }, -}; - -static const NLType rtnl_tca_option_data_htb_types[] = { - [TCA_HTB_PARMS] = { .size = sizeof(struct tc_htb_opt) }, - [TCA_HTB_INIT] = { .size = sizeof(struct tc_htb_glob) }, - [TCA_HTB_CTAB] = { .size = TC_RTAB_SIZE }, - [TCA_HTB_RTAB] = { .size = TC_RTAB_SIZE }, - [TCA_HTB_RATE64] = { .type = NETLINK_TYPE_U64 }, - [TCA_HTB_CEIL64] = { .type = NETLINK_TYPE_U64 }, -}; - -static const NLType rtnl_tca_option_data_pie_types[] = { - [TCA_PIE_LIMIT] = { .type = NETLINK_TYPE_U32 }, -}; - -static const NLType rtnl_tca_option_data_qfq_types[] = { - [TCA_QFQ_WEIGHT] = { .type = NETLINK_TYPE_U32 }, - [TCA_QFQ_LMAX] = { .type = NETLINK_TYPE_U32 }, -}; - -static const NLType rtnl_tca_option_data_sfb_types[] = { - [TCA_SFB_PARMS] = { .size = sizeof(struct tc_sfb_qopt) }, -}; - -static const NLType rtnl_tca_option_data_tbf_types[] = { - [TCA_TBF_PARMS] = { .size = sizeof(struct tc_tbf_qopt) }, - [TCA_TBF_RTAB] = { .size = TC_RTAB_SIZE }, - [TCA_TBF_PTAB] = { .size = TC_RTAB_SIZE }, - [TCA_TBF_RATE64] = { .type = NETLINK_TYPE_U64 }, - [TCA_TBF_PRATE64] = { .type = NETLINK_TYPE_U64 }, - [TCA_TBF_BURST] = { .type = NETLINK_TYPE_U32 }, - [TCA_TBF_PBURST] = { .type = NETLINK_TYPE_U32 }, -}; - -static const char* const nl_union_tca_option_data_table[] = { - [NL_UNION_TCA_OPTION_DATA_CAKE] = "cake", - [NL_UNION_TCA_OPTION_DATA_CODEL] = "codel", - [NL_UNION_TCA_OPTION_DATA_DRR] = "drr", - [NL_UNION_TCA_OPTION_DATA_ETS] = "ets", - [NL_UNION_TCA_OPTION_DATA_FQ] = "fq", - [NL_UNION_TCA_OPTION_DATA_FQ_CODEL] = "fq_codel", - [NL_UNION_TCA_OPTION_DATA_FQ_PIE] = "fq_pie", - [NL_UNION_TCA_OPTION_DATA_GRED] = "gred", - [NL_UNION_TCA_OPTION_DATA_HHF] = "hhf", - [NL_UNION_TCA_OPTION_DATA_HTB] = "htb", - [NL_UNION_TCA_OPTION_DATA_PIE] = "pie", - [NL_UNION_TCA_OPTION_DATA_QFQ] = "qfq", - [NL_UNION_TCA_OPTION_DATA_SFB] = "sfb", - [NL_UNION_TCA_OPTION_DATA_TBF] = "tbf", -}; - -DEFINE_STRING_TABLE_LOOKUP(nl_union_tca_option_data, NLUnionTCAOptionData); - -static const NLTypeSystem rtnl_tca_option_data_type_systems[] = { - [NL_UNION_TCA_OPTION_DATA_CAKE] = { .count = ELEMENTSOF(rtnl_tca_option_data_cake_types), - .types = rtnl_tca_option_data_cake_types }, - [NL_UNION_TCA_OPTION_DATA_CODEL] = { .count = ELEMENTSOF(rtnl_tca_option_data_codel_types), - .types = rtnl_tca_option_data_codel_types }, - [NL_UNION_TCA_OPTION_DATA_DRR] = { .count = ELEMENTSOF(rtnl_tca_option_data_drr_types), - .types = rtnl_tca_option_data_drr_types }, - [NL_UNION_TCA_OPTION_DATA_ETS] = { .count = ELEMENTSOF(rtnl_tca_option_data_ets_types), - .types = rtnl_tca_option_data_ets_types }, - [NL_UNION_TCA_OPTION_DATA_FQ] = { .count = ELEMENTSOF(rtnl_tca_option_data_fq_types), - .types = rtnl_tca_option_data_fq_types }, - [NL_UNION_TCA_OPTION_DATA_FQ_CODEL] = { .count = ELEMENTSOF(rtnl_tca_option_data_fq_codel_types), - .types = rtnl_tca_option_data_fq_codel_types }, - [NL_UNION_TCA_OPTION_DATA_FQ_PIE] = { .count = ELEMENTSOF(rtnl_tca_option_data_fq_pie_types), - .types = rtnl_tca_option_data_fq_pie_types }, - [NL_UNION_TCA_OPTION_DATA_GRED] = { .count = ELEMENTSOF(rtnl_tca_option_data_gred_types), - .types = rtnl_tca_option_data_gred_types }, - [NL_UNION_TCA_OPTION_DATA_HHF] = { .count = ELEMENTSOF(rtnl_tca_option_data_hhf_types), - .types = rtnl_tca_option_data_hhf_types }, - [NL_UNION_TCA_OPTION_DATA_HTB] = { .count = ELEMENTSOF(rtnl_tca_option_data_htb_types), - .types = rtnl_tca_option_data_htb_types }, - [NL_UNION_TCA_OPTION_DATA_PIE] = { .count = ELEMENTSOF(rtnl_tca_option_data_pie_types), - .types = rtnl_tca_option_data_pie_types }, - [NL_UNION_TCA_OPTION_DATA_QFQ] = { .count = ELEMENTSOF(rtnl_tca_option_data_qfq_types), - .types = rtnl_tca_option_data_qfq_types }, - [NL_UNION_TCA_OPTION_DATA_SFB] = { .count = ELEMENTSOF(rtnl_tca_option_data_sfb_types), - .types = rtnl_tca_option_data_sfb_types }, - [NL_UNION_TCA_OPTION_DATA_TBF] = { .count = ELEMENTSOF(rtnl_tca_option_data_tbf_types), - .types = rtnl_tca_option_data_tbf_types }, -}; - -static const NLTypeSystemUnion rtnl_tca_option_data_type_system_union = { - .num = _NL_UNION_TCA_OPTION_DATA_MAX, - .lookup = nl_union_tca_option_data_from_string, - .type_systems = rtnl_tca_option_data_type_systems, - .match_type = NL_MATCH_SIBLING, - .match = TCA_KIND, -}; - -static const NLType rtnl_tca_types[] = { - [TCA_KIND] = { .type = NETLINK_TYPE_STRING }, - [TCA_OPTIONS] = { .type = NETLINK_TYPE_UNION, .type_system_union = &rtnl_tca_option_data_type_system_union }, - [TCA_INGRESS_BLOCK] = { .type = NETLINK_TYPE_U32 }, - [TCA_EGRESS_BLOCK] = { .type = NETLINK_TYPE_U32 }, -}; - -static const NLTypeSystem rtnl_tca_type_system = { - .count = ELEMENTSOF(rtnl_tca_types), - .types = rtnl_tca_types, -}; - -static const NLType mdb_types[] = { - [MDBA_SET_ENTRY] = { .size = sizeof(struct br_port_msg) }, -}; - -static const NLTypeSystem rtnl_mdb_type_system = { - .count = ELEMENTSOF(mdb_types), - .types = mdb_types, -}; +DEFINE_TYPE_SYSTEM(empty); static const NLType error_types[] = { [NLMSGERR_ATTR_MSG] = { .type = NETLINK_TYPE_STRING }, [NLMSGERR_ATTR_OFFS] = { .type = NETLINK_TYPE_U32 }, }; -static const NLTypeSystem error_type_system = { - .count = ELEMENTSOF(error_types), - .types = error_types, -}; - -static const NLType rtnl_types[] = { - [NLMSG_DONE] = { .type = NETLINK_TYPE_NESTED, .type_system = &empty_type_system, .size = 0 }, - [NLMSG_ERROR] = { .type = NETLINK_TYPE_NESTED, .type_system = &error_type_system, .size = sizeof(struct nlmsgerr) }, - [RTM_NEWLINK] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_link_type_system, .size = sizeof(struct ifinfomsg) }, - [RTM_DELLINK] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_link_type_system, .size = sizeof(struct ifinfomsg) }, - [RTM_GETLINK] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_link_type_system, .size = sizeof(struct ifinfomsg) }, - [RTM_SETLINK] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_link_type_system, .size = sizeof(struct ifinfomsg) }, - [RTM_NEWLINKPROP] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_link_type_system, .size = sizeof(struct ifinfomsg) }, - [RTM_DELLINKPROP] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_link_type_system, .size = sizeof(struct ifinfomsg) }, - [RTM_GETLINKPROP] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_link_type_system, .size = sizeof(struct ifinfomsg) }, - [RTM_NEWADDR] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_address_type_system, .size = sizeof(struct ifaddrmsg) }, - [RTM_DELADDR] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_address_type_system, .size = sizeof(struct ifaddrmsg) }, - [RTM_GETADDR] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_address_type_system, .size = sizeof(struct ifaddrmsg) }, - [RTM_NEWROUTE] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_route_type_system, .size = sizeof(struct rtmsg) }, - [RTM_DELROUTE] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_route_type_system, .size = sizeof(struct rtmsg) }, - [RTM_GETROUTE] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_route_type_system, .size = sizeof(struct rtmsg) }, - [RTM_NEWNEIGH] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_neigh_type_system, .size = sizeof(struct ndmsg) }, - [RTM_DELNEIGH] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_neigh_type_system, .size = sizeof(struct ndmsg) }, - [RTM_GETNEIGH] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_neigh_type_system, .size = sizeof(struct ndmsg) }, - [RTM_NEWADDRLABEL] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_addrlabel_type_system, .size = sizeof(struct ifaddrlblmsg) }, - [RTM_DELADDRLABEL] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_addrlabel_type_system, .size = sizeof(struct ifaddrlblmsg) }, - [RTM_GETADDRLABEL] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_addrlabel_type_system, .size = sizeof(struct ifaddrlblmsg) }, - [RTM_NEWRULE] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_routing_policy_rule_type_system, .size = sizeof(struct fib_rule_hdr) }, - [RTM_DELRULE] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_routing_policy_rule_type_system, .size = sizeof(struct fib_rule_hdr) }, - [RTM_GETRULE] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_routing_policy_rule_type_system, .size = sizeof(struct fib_rule_hdr) }, - [RTM_NEWNEXTHOP] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_nexthop_type_system, .size = sizeof(struct nhmsg) }, - [RTM_DELNEXTHOP] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_nexthop_type_system, .size = sizeof(struct nhmsg) }, - [RTM_GETNEXTHOP] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_nexthop_type_system, .size = sizeof(struct nhmsg) }, - [RTM_NEWQDISC] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_tca_type_system, .size = sizeof(struct tcmsg) }, - [RTM_DELQDISC] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_tca_type_system, .size = sizeof(struct tcmsg) }, - [RTM_GETQDISC] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_tca_type_system, .size = sizeof(struct tcmsg) }, - [RTM_NEWTCLASS] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_tca_type_system, .size = sizeof(struct tcmsg) }, - [RTM_DELTCLASS] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_tca_type_system, .size = sizeof(struct tcmsg) }, - [RTM_GETTCLASS] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_tca_type_system, .size = sizeof(struct tcmsg) }, - [RTM_NEWMDB] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_mdb_type_system, .size = sizeof(struct br_port_msg) }, - [RTM_DELMDB] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_mdb_type_system, .size = sizeof(struct br_port_msg) }, - [RTM_GETMDB] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_mdb_type_system, .size = sizeof(struct br_port_msg) }, -}; - -const NLTypeSystem rtnl_type_system_root = { - .count = ELEMENTSOF(rtnl_types), - .types = rtnl_types, -}; - -static const NLType genl_wireguard_allowedip_types[] = { - [WGALLOWEDIP_A_FAMILY] = { .type = NETLINK_TYPE_U16 }, - [WGALLOWEDIP_A_IPADDR] = { .type = NETLINK_TYPE_IN_ADDR }, - [WGALLOWEDIP_A_CIDR_MASK] = { .type = NETLINK_TYPE_U8 }, -}; - -static const NLTypeSystem genl_wireguard_allowedip_type_system = { - .count = ELEMENTSOF(genl_wireguard_allowedip_types), - .types = genl_wireguard_allowedip_types, -}; - -static const NLType genl_wireguard_peer_types[] = { - [WGPEER_A_PUBLIC_KEY] = { .size = WG_KEY_LEN }, - [WGPEER_A_FLAGS] = { .type = NETLINK_TYPE_U32 }, - [WGPEER_A_PRESHARED_KEY] = { .size = WG_KEY_LEN }, - [WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL] = { .type = NETLINK_TYPE_U16 }, - [WGPEER_A_ENDPOINT] = { .type = NETLINK_TYPE_SOCKADDR }, - [WGPEER_A_ALLOWEDIPS] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_wireguard_allowedip_type_system }, -}; - -static const NLTypeSystem genl_wireguard_peer_type_system = { - .count = ELEMENTSOF(genl_wireguard_peer_types), - .types = genl_wireguard_peer_types, -}; - -static const NLType genl_wireguard_set_device_types[] = { - [WGDEVICE_A_IFINDEX] = { .type = NETLINK_TYPE_U32 }, - [WGDEVICE_A_IFNAME] = { .type = NETLINK_TYPE_STRING, .size = IFNAMSIZ-1 }, - [WGDEVICE_A_FLAGS] = { .type = NETLINK_TYPE_U32 }, - [WGDEVICE_A_PRIVATE_KEY] = { .size = WG_KEY_LEN }, - [WGDEVICE_A_LISTEN_PORT] = { .type = NETLINK_TYPE_U16 }, - [WGDEVICE_A_FWMARK] = { .type = NETLINK_TYPE_U32 }, - [WGDEVICE_A_PEERS] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_wireguard_peer_type_system }, -}; - -static const NLTypeSystem genl_wireguard_set_device_type_system = { - .count = ELEMENTSOF(genl_wireguard_set_device_types), - .types = genl_wireguard_set_device_types, -}; - -static const NLType genl_wireguard_cmds[] = { - [WG_CMD_SET_DEVICE] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_wireguard_set_device_type_system }, -}; - -static const NLTypeSystem genl_wireguard_type_system = { - .count = ELEMENTSOF(genl_wireguard_cmds), - .types = genl_wireguard_cmds, -}; - -static const NLType genl_mcast_group_types[] = { - [CTRL_ATTR_MCAST_GRP_NAME] = { .type = NETLINK_TYPE_STRING }, - [CTRL_ATTR_MCAST_GRP_ID] = { .type = NETLINK_TYPE_U32 }, -}; - -static const NLTypeSystem genl_mcast_group_type_system = { - .count = ELEMENTSOF(genl_mcast_group_types), - .types = genl_mcast_group_types, -}; - -static const NLType genl_get_family_types[] = { - [CTRL_ATTR_FAMILY_NAME] = { .type = NETLINK_TYPE_STRING }, - [CTRL_ATTR_FAMILY_ID] = { .type = NETLINK_TYPE_U16 }, - [CTRL_ATTR_MCAST_GROUPS] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_mcast_group_type_system }, -}; - -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_fou_types[] = { - [FOU_ATTR_PORT] = { .type = NETLINK_TYPE_U16 }, - [FOU_ATTR_AF] = { .type = NETLINK_TYPE_U8 }, - [FOU_ATTR_IPPROTO] = { .type = NETLINK_TYPE_U8 }, - [FOU_ATTR_TYPE] = { .type = NETLINK_TYPE_U8 }, - [FOU_ATTR_REMCSUM_NOPARTIAL] = { .type = NETLINK_TYPE_FLAG }, - [FOU_ATTR_LOCAL_V4] = { .type = NETLINK_TYPE_IN_ADDR }, - [FOU_ATTR_PEER_V4] = { .type = NETLINK_TYPE_IN_ADDR }, - [FOU_ATTR_LOCAL_V6] = { .type = NETLINK_TYPE_IN_ADDR }, - [FOU_ATTR_PEER_V6] = { .type = NETLINK_TYPE_IN_ADDR}, - [FOU_ATTR_PEER_PORT] = { .type = NETLINK_TYPE_U16}, - [FOU_ATTR_IFINDEX] = { .type = NETLINK_TYPE_U32}, -}; - -static const NLTypeSystem genl_fou_type_system = { - .count = ELEMENTSOF(genl_fou_types), - .types = genl_fou_types, -}; - -static const NLType genl_fou_cmds[] = { - [FOU_CMD_ADD] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_fou_type_system }, - [FOU_CMD_DEL] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_fou_type_system }, - [FOU_CMD_GET] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_fou_type_system }, -}; - -static const NLTypeSystem genl_fou_cmds_type_system = { - .count = ELEMENTSOF(genl_fou_cmds), - .types = genl_fou_cmds, -}; - -static const NLType genl_l2tp_types[] = { - [L2TP_ATTR_PW_TYPE] = { .type = NETLINK_TYPE_U16 }, - [L2TP_ATTR_ENCAP_TYPE] = { .type = NETLINK_TYPE_U16 }, - [L2TP_ATTR_OFFSET] = { .type = NETLINK_TYPE_U16 }, - [L2TP_ATTR_DATA_SEQ] = { .type = NETLINK_TYPE_U16 }, - [L2TP_ATTR_L2SPEC_TYPE] = { .type = NETLINK_TYPE_U8 }, - [L2TP_ATTR_L2SPEC_LEN] = { .type = NETLINK_TYPE_U8 }, - [L2TP_ATTR_PROTO_VERSION] = { .type = NETLINK_TYPE_U8 }, - [L2TP_ATTR_IFNAME] = { .type = NETLINK_TYPE_STRING }, - [L2TP_ATTR_CONN_ID] = { .type = NETLINK_TYPE_U32 }, - [L2TP_ATTR_PEER_CONN_ID] = { .type = NETLINK_TYPE_U32 }, - [L2TP_ATTR_SESSION_ID] = { .type = NETLINK_TYPE_U32 }, - [L2TP_ATTR_PEER_SESSION_ID] = { .type = NETLINK_TYPE_U32 }, - [L2TP_ATTR_UDP_CSUM] = { .type = NETLINK_TYPE_U8 }, - [L2TP_ATTR_VLAN_ID] = { .type = NETLINK_TYPE_U16 }, - [L2TP_ATTR_RECV_SEQ] = { .type = NETLINK_TYPE_U8 }, - [L2TP_ATTR_SEND_SEQ] = { .type = NETLINK_TYPE_U8 }, - [L2TP_ATTR_LNS_MODE] = { .type = NETLINK_TYPE_U8 }, - [L2TP_ATTR_USING_IPSEC] = { .type = NETLINK_TYPE_U8 }, - [L2TP_ATTR_FD] = { .type = NETLINK_TYPE_U32 }, - [L2TP_ATTR_IP_SADDR] = { .type = NETLINK_TYPE_IN_ADDR }, - [L2TP_ATTR_IP_DADDR] = { .type = NETLINK_TYPE_IN_ADDR }, - [L2TP_ATTR_UDP_SPORT] = { .type = NETLINK_TYPE_U16 }, - [L2TP_ATTR_UDP_DPORT] = { .type = NETLINK_TYPE_U16 }, - [L2TP_ATTR_IP6_SADDR] = { .type = NETLINK_TYPE_IN_ADDR }, - [L2TP_ATTR_IP6_DADDR] = { .type = NETLINK_TYPE_IN_ADDR }, - [L2TP_ATTR_UDP_ZERO_CSUM6_TX] = { .type = NETLINK_TYPE_FLAG }, - [L2TP_ATTR_UDP_ZERO_CSUM6_RX] = { .type = NETLINK_TYPE_FLAG }, -}; - -static const NLTypeSystem genl_l2tp_type_system = { - .count = ELEMENTSOF(genl_l2tp_types), - .types = genl_l2tp_types, -}; - -static const NLType genl_l2tp[] = { - [L2TP_CMD_TUNNEL_CREATE] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_l2tp_type_system }, - [L2TP_CMD_TUNNEL_DELETE] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_l2tp_type_system }, - [L2TP_CMD_TUNNEL_MODIFY] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_l2tp_type_system }, - [L2TP_CMD_TUNNEL_GET] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_l2tp_type_system }, - [L2TP_CMD_SESSION_CREATE] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_l2tp_type_system }, - [L2TP_CMD_SESSION_DELETE] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_l2tp_type_system }, - [L2TP_CMD_SESSION_MODIFY] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_l2tp_type_system }, - [L2TP_CMD_SESSION_GET] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_l2tp_type_system }, -}; - -static const NLTypeSystem genl_l2tp_tunnel_session_type_system = { - .count = ELEMENTSOF(genl_l2tp), - .types = genl_l2tp, -}; - -static const NLType genl_rxsc_types[] = { - [MACSEC_RXSC_ATTR_SCI] = { .type = NETLINK_TYPE_U64 }, -}; - -static const NLTypeSystem genl_rxsc_config_type_system = { - .count = ELEMENTSOF(genl_rxsc_types), - .types = genl_rxsc_types, -}; - -static const NLType genl_macsec_rxsc_types[] = { - [MACSEC_ATTR_IFINDEX] = { .type = NETLINK_TYPE_U32 }, - [MACSEC_ATTR_RXSC_CONFIG] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_rxsc_config_type_system }, -}; - -static const NLTypeSystem genl_macsec_rxsc_type_system = { - .count = ELEMENTSOF(genl_macsec_rxsc_types), - .types = genl_macsec_rxsc_types, -}; - -static const NLType genl_macsec_sa_config_types[] = { - [MACSEC_SA_ATTR_AN] = { .type = NETLINK_TYPE_U8 }, - [MACSEC_SA_ATTR_ACTIVE] = { .type = NETLINK_TYPE_U8 }, - [MACSEC_SA_ATTR_PN] = { .type = NETLINK_TYPE_U32 }, - [MACSEC_SA_ATTR_KEYID] = { .size = MACSEC_KEYID_LEN }, - [MACSEC_SA_ATTR_KEY] = { .size = MACSEC_MAX_KEY_LEN }, -}; +DEFINE_TYPE_SYSTEM(error); -static const NLTypeSystem genl_macsec_sa_config_type_system = { - .count = ELEMENTSOF(genl_macsec_sa_config_types), - .types = genl_macsec_sa_config_types, +static const NLType basic_types[] = { + [NLMSG_DONE] = { .type = NETLINK_TYPE_NESTED, .type_system = &empty_type_system }, + [NLMSG_ERROR] = { .type = NETLINK_TYPE_NESTED, .type_system = &error_type_system, .size = sizeof(struct nlmsgerr) }, }; -static const NLType genl_macsec_rxsa_types[] = { - [MACSEC_ATTR_IFINDEX] = { .type = NETLINK_TYPE_U32 }, - [MACSEC_ATTR_SA_CONFIG] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_macsec_sa_config_type_system }, -}; - -static const NLTypeSystem genl_macsec_rxsa_type_system = { - .count = ELEMENTSOF(genl_macsec_rxsa_types), - .types = genl_macsec_rxsa_types, -}; - -static const NLType genl_macsec_sa_types[] = { - [MACSEC_ATTR_IFINDEX] = { .type = NETLINK_TYPE_U32 }, - [MACSEC_ATTR_RXSC_CONFIG] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_rxsc_config_type_system }, - [MACSEC_ATTR_SA_CONFIG] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_macsec_sa_config_type_system }, -}; - -static const NLTypeSystem genl_macsec_sa_type_system = { - .count = ELEMENTSOF(genl_macsec_sa_types), - .types = genl_macsec_sa_types, -}; - -static const NLType genl_macsec[] = { - [MACSEC_CMD_ADD_RXSC] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_macsec_rxsc_type_system }, - [MACSEC_CMD_ADD_TXSA] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_macsec_rxsa_type_system}, - [MACSEC_CMD_ADD_RXSA] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_macsec_sa_type_system }, -}; - -static const NLTypeSystem genl_macsec_device_type_system = { - .count = ELEMENTSOF(genl_macsec), - .types = genl_macsec, -}; - -static const NLType genl_nl80211_types[] = { - [NL80211_ATTR_IFINDEX] = { .type = NETLINK_TYPE_U32 }, - [NL80211_ATTR_MAC] = { .type = NETLINK_TYPE_ETHER_ADDR }, - [NL80211_ATTR_SSID] = { .type = NETLINK_TYPE_STRING }, - [NL80211_ATTR_IFTYPE] = { .type = NETLINK_TYPE_U32 }, -}; - -static const NLTypeSystem genl_nl80211_type_system = { - .count = ELEMENTSOF(genl_nl80211_types), - .types = genl_nl80211_types, -}; - -static const NLType genl_nl80211_cmds[] = { - [NL80211_CMD_GET_WIPHY] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_nl80211_type_system }, - [NL80211_CMD_SET_WIPHY] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_nl80211_type_system }, - [NL80211_CMD_NEW_WIPHY] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_nl80211_type_system }, - [NL80211_CMD_DEL_WIPHY] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_nl80211_type_system }, - [NL80211_CMD_GET_INTERFACE] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_nl80211_type_system }, - [NL80211_CMD_SET_INTERFACE] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_nl80211_type_system }, - [NL80211_CMD_NEW_INTERFACE] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_nl80211_type_system }, - [NL80211_CMD_DEL_INTERFACE] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_nl80211_type_system }, - [NL80211_CMD_GET_STATION] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_nl80211_type_system }, - [NL80211_CMD_SET_STATION] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_nl80211_type_system }, - [NL80211_CMD_NEW_STATION] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_nl80211_type_system }, - [NL80211_CMD_DEL_STATION] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_nl80211_type_system }, -}; - -static const NLTypeSystem genl_nl80211_cmds_type_system = { - .count = ELEMENTSOF(genl_nl80211_cmds), - .types = genl_nl80211_cmds, -}; - -static const NLType genl_batadv_types[] = { - [BATADV_ATTR_VERSION] = { .type = NETLINK_TYPE_STRING }, - [BATADV_ATTR_ALGO_NAME] = { .type = NETLINK_TYPE_STRING }, - [BATADV_ATTR_MESH_IFINDEX] = { .type = NETLINK_TYPE_U32 }, - [BATADV_ATTR_MESH_IFNAME] = { .type = NETLINK_TYPE_STRING, .size = IFNAMSIZ }, - [BATADV_ATTR_MESH_ADDRESS] = { .size = ETH_ALEN }, - [BATADV_ATTR_HARD_IFINDEX] = { .type = NETLINK_TYPE_U32 }, - [BATADV_ATTR_HARD_IFNAME] = { .type = NETLINK_TYPE_STRING, .size = IFNAMSIZ }, - [BATADV_ATTR_HARD_ADDRESS] = { .size = ETH_ALEN }, - [BATADV_ATTR_ORIG_ADDRESS] = { .size = ETH_ALEN }, - [BATADV_ATTR_TPMETER_RESULT] = { .type = NETLINK_TYPE_U8 }, - [BATADV_ATTR_TPMETER_TEST_TIME] = { .type = NETLINK_TYPE_U32 }, - [BATADV_ATTR_TPMETER_BYTES] = { .type = NETLINK_TYPE_U64 }, - [BATADV_ATTR_TPMETER_COOKIE] = { .type = NETLINK_TYPE_U32 }, - [BATADV_ATTR_PAD] = { .type = NETLINK_TYPE_UNSPEC }, - [BATADV_ATTR_ACTIVE] = { .type = NETLINK_TYPE_FLAG }, - [BATADV_ATTR_TT_ADDRESS] = { .size = ETH_ALEN }, - [BATADV_ATTR_TT_TTVN] = { .type = NETLINK_TYPE_U8 }, - [BATADV_ATTR_TT_LAST_TTVN] = { .type = NETLINK_TYPE_U8 }, - [BATADV_ATTR_TT_CRC32] = { .type = NETLINK_TYPE_U32 }, - [BATADV_ATTR_TT_VID] = { .type = NETLINK_TYPE_U16 }, - [BATADV_ATTR_TT_FLAGS] = { .type = NETLINK_TYPE_U32 }, - [BATADV_ATTR_FLAG_BEST] = { .type = NETLINK_TYPE_FLAG }, - [BATADV_ATTR_LAST_SEEN_MSECS] = { .type = NETLINK_TYPE_U32 }, - [BATADV_ATTR_NEIGH_ADDRESS] = { .size = ETH_ALEN }, - [BATADV_ATTR_TQ] = { .type = NETLINK_TYPE_U8 }, - [BATADV_ATTR_THROUGHPUT] = { .type = NETLINK_TYPE_U32 }, - [BATADV_ATTR_BANDWIDTH_UP] = { .type = NETLINK_TYPE_U32 }, - [BATADV_ATTR_BANDWIDTH_DOWN] = { .type = NETLINK_TYPE_U32 }, - [BATADV_ATTR_ROUTER] = { .size = ETH_ALEN }, - [BATADV_ATTR_BLA_OWN] = { .type = NETLINK_TYPE_FLAG }, - [BATADV_ATTR_BLA_ADDRESS] = { .size = ETH_ALEN }, - [BATADV_ATTR_BLA_VID] = { .type = NETLINK_TYPE_U16 }, - [BATADV_ATTR_BLA_BACKBONE] = { .size = ETH_ALEN }, - [BATADV_ATTR_BLA_CRC] = { .type = NETLINK_TYPE_U16 }, - [BATADV_ATTR_DAT_CACHE_IP4ADDRESS] = { .type = NETLINK_TYPE_U32 }, - [BATADV_ATTR_DAT_CACHE_HWADDRESS] = { .size = ETH_ALEN }, - [BATADV_ATTR_DAT_CACHE_VID] = { .type = NETLINK_TYPE_U16 }, - [BATADV_ATTR_MCAST_FLAGS] = { .type = NETLINK_TYPE_U32 }, - [BATADV_ATTR_MCAST_FLAGS_PRIV] = { .type = NETLINK_TYPE_U32 }, - [BATADV_ATTR_VLANID] = { .type = NETLINK_TYPE_U16 }, - [BATADV_ATTR_AGGREGATED_OGMS_ENABLED] = { .type = NETLINK_TYPE_U8 }, - [BATADV_ATTR_AP_ISOLATION_ENABLED] = { .type = NETLINK_TYPE_U8 }, - [BATADV_ATTR_ISOLATION_MARK] = { .type = NETLINK_TYPE_U32 }, - [BATADV_ATTR_ISOLATION_MASK] = { .type = NETLINK_TYPE_U32 }, - [BATADV_ATTR_BONDING_ENABLED] = { .type = NETLINK_TYPE_U8 }, - [BATADV_ATTR_BRIDGE_LOOP_AVOIDANCE_ENABLED] = { .type = NETLINK_TYPE_U8 }, - [BATADV_ATTR_DISTRIBUTED_ARP_TABLE_ENABLED] = { .type = NETLINK_TYPE_U8 }, - [BATADV_ATTR_FRAGMENTATION_ENABLED] = { .type = NETLINK_TYPE_U8 }, - [BATADV_ATTR_GW_BANDWIDTH_DOWN] = { .type = NETLINK_TYPE_U32 }, - [BATADV_ATTR_GW_BANDWIDTH_UP] = { .type = NETLINK_TYPE_U32 }, - [BATADV_ATTR_GW_MODE] = { .type = NETLINK_TYPE_U8 }, - [BATADV_ATTR_GW_SEL_CLASS] = { .type = NETLINK_TYPE_U32 }, - [BATADV_ATTR_HOP_PENALTY] = { .type = NETLINK_TYPE_U8 }, - [BATADV_ATTR_LOG_LEVEL] = { .type = NETLINK_TYPE_U32 }, - [BATADV_ATTR_MULTICAST_FORCEFLOOD_ENABLED] = { .type = NETLINK_TYPE_U8 }, - [BATADV_ATTR_MULTICAST_FANOUT] = { .type = NETLINK_TYPE_U32 }, - [BATADV_ATTR_NETWORK_CODING_ENABLED] = { .type = NETLINK_TYPE_U8 }, - [BATADV_ATTR_ORIG_INTERVAL] = { .type = NETLINK_TYPE_U32 }, - [BATADV_ATTR_ELP_INTERVAL] = { .type = NETLINK_TYPE_U32 }, - [BATADV_ATTR_THROUGHPUT_OVERRIDE] = { .type = NETLINK_TYPE_U32 }, -}; - -static const NLTypeSystem genl_batadv_type_system = { - .count = ELEMENTSOF(genl_batadv_types), - .types = genl_batadv_types, -}; - -static const NLType genl_batadv_cmds[] = { - [BATADV_CMD_SET_MESH] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_batadv_type_system }, -}; - -static const NLTypeSystem genl_batadv_cmds_type_system = { - .count = ELEMENTSOF(genl_batadv_cmds), - .types = genl_batadv_cmds, -}; - -static const NLType genl_families[] = { - [SD_GENL_ID_CTRL] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_ctrl_id_ctrl_type_system }, - [SD_GENL_WIREGUARD] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_wireguard_type_system }, - [SD_GENL_FOU] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_fou_cmds_type_system }, - [SD_GENL_L2TP] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_l2tp_tunnel_session_type_system }, - [SD_GENL_MACSEC] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_macsec_device_type_system }, - [SD_GENL_NL80211] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_nl80211_cmds_type_system }, - [SD_GENL_BATADV] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_batadv_cmds_type_system }, -}; - -static const NLType nfnl_nft_table_types[] = { - [NFTA_TABLE_NAME] = { .type = NETLINK_TYPE_STRING, .size = NFT_TABLE_MAXNAMELEN - 1 }, - [NFTA_TABLE_FLAGS] = { .type = NETLINK_TYPE_U32 }, -}; - -static const NLTypeSystem nfnl_nft_table_type_system = { - .count = ELEMENTSOF(nfnl_nft_table_types), - .types = nfnl_nft_table_types, -}; - -static const NLType nfnl_nft_chain_hook_types[] = { - [NFTA_HOOK_HOOKNUM] = { .type = NETLINK_TYPE_U32 }, - [NFTA_HOOK_PRIORITY] = { .type = NETLINK_TYPE_U32 }, - [NFTA_HOOK_DEV] = { .type = NETLINK_TYPE_STRING, .size = IFNAMSIZ - 1 }, -}; - -static const NLTypeSystem nfnl_nft_chain_hook_type_system = { - .count = ELEMENTSOF(nfnl_nft_chain_hook_types), - .types = nfnl_nft_chain_hook_types, -}; - -static const NLType nfnl_nft_chain_types[] = { - [NFTA_CHAIN_TABLE] = { .type = NETLINK_TYPE_STRING, .size = NFT_TABLE_MAXNAMELEN - 1 }, - [NFTA_CHAIN_NAME] = { .type = NETLINK_TYPE_STRING, .size = NFT_TABLE_MAXNAMELEN - 1 }, - [NFTA_CHAIN_HOOK] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_chain_hook_type_system }, - [NFTA_CHAIN_TYPE] = { .type = NETLINK_TYPE_STRING, .size = 16 }, - [NFTA_CHAIN_FLAGS] = { .type = NETLINK_TYPE_U32 }, -}; - -static const NLTypeSystem nfnl_nft_chain_type_system = { - .count = ELEMENTSOF(nfnl_nft_chain_types), - .types = nfnl_nft_chain_types, -}; - -static const NLType nfnl_nft_expr_meta_types[] = { - [NFTA_META_DREG] = { .type = NETLINK_TYPE_U32 }, - [NFTA_META_KEY] = { .type = NETLINK_TYPE_U32 }, - [NFTA_META_SREG] = { .type = NETLINK_TYPE_U32 }, -}; - -static const NLType nfnl_nft_expr_payload_types[] = { - [NFTA_PAYLOAD_DREG] = { .type = NETLINK_TYPE_U32 }, - [NFTA_PAYLOAD_BASE] = { .type = NETLINK_TYPE_U32 }, - [NFTA_PAYLOAD_OFFSET] = { .type = NETLINK_TYPE_U32 }, - [NFTA_PAYLOAD_LEN] = { .type = NETLINK_TYPE_U32 }, -}; - -static const NLType nfnl_nft_expr_nat_types[] = { - [NFTA_NAT_TYPE] = { .type = NETLINK_TYPE_U32 }, - [NFTA_NAT_FAMILY] = { .type = NETLINK_TYPE_U32 }, - [NFTA_NAT_REG_ADDR_MIN] = { .type = NETLINK_TYPE_U32 }, - [NFTA_NAT_REG_ADDR_MAX] = { .type = NETLINK_TYPE_U32 }, - [NFTA_NAT_REG_PROTO_MIN] = { .type = NETLINK_TYPE_U32 }, - [NFTA_NAT_REG_PROTO_MAX] = { .type = NETLINK_TYPE_U32 }, - [NFTA_NAT_FLAGS] = { .type = NETLINK_TYPE_U32 }, -}; - -static const NLType nfnl_nft_data_types[] = { - [NFTA_DATA_VALUE] = { .type = NETLINK_TYPE_BINARY }, -}; - -static const NLTypeSystem nfnl_nft_data_type_system = { - .count = ELEMENTSOF(nfnl_nft_data_types), - .types = nfnl_nft_data_types, -}; - -static const NLType nfnl_nft_expr_bitwise_types[] = { - [NFTA_BITWISE_SREG] = { .type = NETLINK_TYPE_U32 }, - [NFTA_BITWISE_DREG] = { .type = NETLINK_TYPE_U32 }, - [NFTA_BITWISE_LEN] = { .type = NETLINK_TYPE_U32 }, - [NFTA_BITWISE_MASK] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_data_type_system }, - [NFTA_BITWISE_XOR] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_data_type_system }, -}; - -static const NLType nfnl_nft_expr_cmp_types[] = { - [NFTA_CMP_SREG] = { .type = NETLINK_TYPE_U32 }, - [NFTA_CMP_OP] = { .type = NETLINK_TYPE_U32 }, - [NFTA_CMP_DATA] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_data_type_system }, -}; - -static const NLType nfnl_nft_expr_fib_types[] = { - [NFTA_FIB_DREG] = { .type = NETLINK_TYPE_U32 }, - [NFTA_FIB_RESULT] = { .type = NETLINK_TYPE_U32 }, - [NFTA_FIB_FLAGS] = { .type = NETLINK_TYPE_U32 }, -}; - -static const NLType nfnl_nft_expr_lookup_types[] = { - [NFTA_LOOKUP_SET] = { .type = NETLINK_TYPE_STRING }, - [NFTA_LOOKUP_SREG] = { .type = NETLINK_TYPE_U32 }, - [NFTA_LOOKUP_DREG] = { .type = NETLINK_TYPE_U32 }, - [NFTA_LOOKUP_FLAGS] = { .type = NETLINK_TYPE_U32 }, -}; - -static const NLType nfnl_nft_expr_masq_types[] = { - [NFTA_MASQ_FLAGS] = { .type = NETLINK_TYPE_U32 }, - [NFTA_MASQ_REG_PROTO_MIN] = { .type = NETLINK_TYPE_U32 }, - [NFTA_MASQ_REG_PROTO_MAX] = { .type = NETLINK_TYPE_U32 }, -}; - -static const NLTypeSystem nfnl_expr_data_type_systems[] = { - [NL_UNION_NFT_EXPR_DATA_BITWISE] = { .count = ELEMENTSOF(nfnl_nft_expr_bitwise_types), - .types = nfnl_nft_expr_bitwise_types }, - [NL_UNION_NFT_EXPR_DATA_CMP] = { .count = ELEMENTSOF(nfnl_nft_expr_cmp_types), - .types = nfnl_nft_expr_cmp_types }, - [NL_UNION_NFT_EXPR_DATA_FIB] = { .count = ELEMENTSOF(nfnl_nft_expr_fib_types), - .types = nfnl_nft_expr_fib_types }, - [NL_UNION_NFT_EXPR_DATA_LOOKUP] = { .count = ELEMENTSOF(nfnl_nft_expr_lookup_types), - .types = nfnl_nft_expr_lookup_types }, - [NL_UNION_NFT_EXPR_DATA_MASQ] = { .count = ELEMENTSOF(nfnl_nft_expr_masq_types), - .types = nfnl_nft_expr_masq_types }, - [NL_UNION_NFT_EXPR_DATA_META] = { .count = ELEMENTSOF(nfnl_nft_expr_meta_types), - .types = nfnl_nft_expr_meta_types }, - [NL_UNION_NFT_EXPR_DATA_NAT] = { .count = ELEMENTSOF(nfnl_nft_expr_nat_types), - .types = nfnl_nft_expr_nat_types }, - [NL_UNION_NFT_EXPR_DATA_PAYLOAD] = { .count = ELEMENTSOF(nfnl_nft_expr_payload_types), - .types = nfnl_nft_expr_payload_types }, -}; - -static const char* const nl_union_nft_expr_data_table[] = { - [NL_UNION_NFT_EXPR_DATA_BITWISE] = "bitwise", - [NL_UNION_NFT_EXPR_DATA_CMP] = "cmp", - [NL_UNION_NFT_EXPR_DATA_LOOKUP] = "lookup", - [NL_UNION_NFT_EXPR_DATA_META] = "meta", - [NL_UNION_NFT_EXPR_DATA_FIB] = "fib", - [NL_UNION_NFT_EXPR_DATA_MASQ] = "masq", - [NL_UNION_NFT_EXPR_DATA_NAT] = "nat", - [NL_UNION_NFT_EXPR_DATA_PAYLOAD] = "payload", -}; - -DEFINE_STRING_TABLE_LOOKUP(nl_union_nft_expr_data, NLUnionNFTExprData); - -static const NLTypeSystemUnion nfnl_nft_data_expr_type_system_union = { - .num = _NL_UNION_NFT_EXPR_DATA_MAX, - .lookup = nl_union_nft_expr_data_from_string, - .type_systems = nfnl_expr_data_type_systems, - .match_type = NL_MATCH_SIBLING, - .match = NFTA_EXPR_NAME, -}; - -static const NLType nfnl_nft_rule_expr_types[] = { - [NFTA_EXPR_NAME] = { .type = NETLINK_TYPE_STRING, .size = 16 }, - [NFTA_EXPR_DATA] = { .type = NETLINK_TYPE_UNION, - .type_system_union = &nfnl_nft_data_expr_type_system_union }, -}; - -static const NLTypeSystem nfnl_nft_rule_expr_type_system = { - .count = ELEMENTSOF(nfnl_nft_rule_expr_types), - .types = nfnl_nft_rule_expr_types, -}; - -static const NLType nfnl_nft_rule_types[] = { - [NFTA_RULE_TABLE] = { .type = NETLINK_TYPE_STRING, .size = NFT_TABLE_MAXNAMELEN - 1 }, - [NFTA_RULE_CHAIN] = { .type = NETLINK_TYPE_STRING, .size = NFT_TABLE_MAXNAMELEN - 1 }, - [NFTA_RULE_EXPRESSIONS] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_rule_expr_type_system } -}; - -static const NLTypeSystem nfnl_nft_rule_type_system = { - .count = ELEMENTSOF(nfnl_nft_rule_types), - .types = nfnl_nft_rule_types, -}; - -static const NLType nfnl_nft_set_types[] = { - [NFTA_SET_TABLE] = { .type = NETLINK_TYPE_STRING, .size = NFT_TABLE_MAXNAMELEN - 1 }, - [NFTA_SET_NAME] = { .type = NETLINK_TYPE_STRING, .size = NFT_TABLE_MAXNAMELEN - 1 }, - [NFTA_SET_FLAGS] = { .type = NETLINK_TYPE_U32 }, - [NFTA_SET_KEY_TYPE] = { .type = NETLINK_TYPE_U32 }, - [NFTA_SET_KEY_LEN] = { .type = NETLINK_TYPE_U32 }, - [NFTA_SET_DATA_TYPE] = { .type = NETLINK_TYPE_U32 }, - [NFTA_SET_DATA_LEN] = { .type = NETLINK_TYPE_U32 }, - [NFTA_SET_POLICY] = { .type = NETLINK_TYPE_U32 }, - [NFTA_SET_ID] = { .type = NETLINK_TYPE_U32 }, -}; - -static const NLTypeSystem nfnl_nft_set_type_system = { - .count = ELEMENTSOF(nfnl_nft_set_types), - .types = nfnl_nft_set_types, -}; - -static const NLType nfnl_nft_setelem_types[] = { - [NFTA_SET_ELEM_KEY] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_data_type_system }, - [NFTA_SET_ELEM_DATA] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_data_type_system }, - [NFTA_SET_ELEM_FLAGS] = { .type = NETLINK_TYPE_U32 }, -}; - -static const NLTypeSystem nfnl_nft_setelem_type_system = { - .count = ELEMENTSOF(nfnl_nft_setelem_types), - .types = nfnl_nft_setelem_types, -}; - -static const NLType nfnl_nft_setelem_list_types[] = { - [NFTA_SET_ELEM_LIST_TABLE] = { .type = NETLINK_TYPE_STRING, .size = NFT_TABLE_MAXNAMELEN - 1 }, - [NFTA_SET_ELEM_LIST_SET] = { .type = NETLINK_TYPE_STRING, .size = NFT_TABLE_MAXNAMELEN - 1 }, - [NFTA_SET_ELEM_LIST_ELEMENTS] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_setelem_type_system }, -}; - -static const NLTypeSystem nfnl_nft_setelem_list_type_system = { - .count = ELEMENTSOF(nfnl_nft_setelem_list_types), - .types = nfnl_nft_setelem_list_types, -}; - -static const NLType nfnl_nft_msg_types [] = { - [NFT_MSG_DELTABLE] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_table_type_system, .size = sizeof(struct nfgenmsg) }, - [NFT_MSG_NEWTABLE] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_table_type_system, .size = sizeof(struct nfgenmsg) }, - [NFT_MSG_NEWCHAIN] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_chain_type_system, .size = sizeof(struct nfgenmsg) }, - [NFT_MSG_NEWRULE] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_rule_type_system, .size = sizeof(struct nfgenmsg) }, - [NFT_MSG_NEWSET] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_set_type_system, .size = sizeof(struct nfgenmsg) }, - [NFT_MSG_NEWSETELEM] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_setelem_list_type_system, .size = sizeof(struct nfgenmsg) }, - [NFT_MSG_DELSETELEM] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_setelem_list_type_system, .size = sizeof(struct nfgenmsg) }, -}; - -static const NLTypeSystem nfnl_nft_msg_type_system = { - .count = ELEMENTSOF(nfnl_nft_msg_types), - .types = nfnl_nft_msg_types, -}; - -static const NLType nfnl_msg_batch_types [] = { - [NFNL_BATCH_GENID] = { .type = NETLINK_TYPE_U32 } -}; - -static const NLTypeSystem nfnl_msg_batch_type_system = { - .count = ELEMENTSOF(nfnl_msg_batch_types), - .types = nfnl_msg_batch_types, -}; - -static const NLType nfnl_types[] = { - [NLMSG_DONE] = { .type = NETLINK_TYPE_NESTED, .type_system = &empty_type_system, .size = 0 }, - [NLMSG_ERROR] = { .type = NETLINK_TYPE_NESTED, .type_system = &error_type_system, .size = sizeof(struct nlmsgerr) }, - [NFNL_MSG_BATCH_BEGIN] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_msg_batch_type_system, .size = sizeof(struct nfgenmsg) }, - [NFNL_MSG_BATCH_END] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_msg_batch_type_system, .size = sizeof(struct nfgenmsg) }, - [NFNL_SUBSYS_NFTABLES] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_msg_type_system, .size = sizeof(struct nfgenmsg) }, -}; - -const NLTypeSystem nfnl_type_system_root = { - .count = ELEMENTSOF(nfnl_types), - .types = nfnl_types, -}; - -/* Mainly used when sending message */ -const NLTypeSystem genl_family_type_system_root = { - .count = ELEMENTSOF(genl_families), - .types = genl_families, -}; - -static const NLType genl_types[] = { - [SD_GENL_ERROR] = { .type = NETLINK_TYPE_NESTED, .type_system = &error_type_system, .size = sizeof(struct nlmsgerr) }, - [SD_GENL_DONE] = { .type = NETLINK_TYPE_NESTED, .type_system = &empty_type_system }, - [SD_GENL_ID_CTRL] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_get_family_type_system, .size = sizeof(struct genlmsghdr) }, - [SD_GENL_NL80211] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_nl80211_type_system, .size = sizeof(struct genlmsghdr) }, -}; - -/* Mainly used when message received */ -const NLTypeSystem genl_type_system_root = { - .count = ELEMENTSOF(genl_types), - .types = genl_types, -}; +DEFINE_TYPE_SYSTEM(basic); uint16_t type_get_type(const NLType *type) { assert(type); @@ -1700,153 +36,127 @@ size_t type_get_size(const NLType *type) { return type->size; } -void type_get_type_system(const NLType *nl_type, const NLTypeSystem **ret) { +const NLTypeSystem *type_get_type_system(const NLType *nl_type) { assert(nl_type); - assert(ret); assert(nl_type->type == NETLINK_TYPE_NESTED); assert(nl_type->type_system); - - *ret = nl_type->type_system; + return nl_type->type_system; } -void type_get_type_system_union(const NLType *nl_type, const NLTypeSystemUnion **ret) { +const NLTypeSystemUnion *type_get_type_system_union(const NLType *nl_type) { assert(nl_type); - assert(ret); assert(nl_type->type == NETLINK_TYPE_UNION); assert(nl_type->type_system_union); - - *ret = nl_type->type_system_union; -} - -uint16_t type_system_get_count(const NLTypeSystem *type_system) { - assert(type_system); - return type_system->count; + return nl_type->type_system_union; } -const NLTypeSystem *type_system_get_root(int protocol) { - switch (protocol) { - case NETLINK_GENERIC: - return &genl_type_system_root; - case NETLINK_NETFILTER: - return &nfnl_type_system_root; - default: /* NETLINK_ROUTE: */ - return &rtnl_type_system_root; - } -} +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) { -int type_system_root_get_type(sd_netlink *nl, const NLType **ret, uint16_t type) { - sd_genl_family_t family; const NLType *nl_type; - int r; - - if (!nl) - return type_system_get_type(&rtnl_type_system_root, ret, type); - - if (nl->protocol != NETLINK_GENERIC) - return type_system_get_type(type_system_get_root(nl->protocol), ret, type); - r = nlmsg_type_to_genl_family(nl, type, &family); - if (r < 0) - return r; + assert(nl); - if (family >= genl_type_system_root.count) + if (IN_SET(type, NLMSG_DONE, NLMSG_ERROR)) + nl_type = type_system_get_type(&basic_type_system, type); + else + switch(nl->protocol) { + case NETLINK_ROUTE: + nl_type = rtnl_get_type(type); + break; + case NETLINK_NETFILTER: + nl_type = nfnl_get_type(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 (!nl_type) return -EOPNOTSUPP; - nl_type = &genl_type_system_root.types[family]; - - if (nl_type->type == NETLINK_TYPE_UNSPEC) + if (type_get_type(nl_type) != NETLINK_TYPE_NESTED) return -EOPNOTSUPP; - *ret = nl_type; - + 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) { +const NLType *type_system_get_type(const NLTypeSystem *type_system, uint16_t type) { const NLType *nl_type; - assert(ret); assert(type_system); assert(type_system->types); if (type >= type_system->count) - return -EOPNOTSUPP; + return NULL; nl_type = &type_system->types[type]; if (nl_type->type == NETLINK_TYPE_UNSPEC) - return -EOPNOTSUPP; - - *ret = nl_type; + return NULL; - return 0; + return nl_type; } -int type_system_get_type_system(const NLTypeSystem *type_system, const NLTypeSystem **ret, uint16_t type) { +const NLTypeSystem *type_system_get_type_system(const NLTypeSystem *type_system, uint16_t type) { const NLType *nl_type; - int r; - assert(ret); + nl_type = type_system_get_type(type_system, type); + if (!nl_type) + return NULL; - r = type_system_get_type(type_system, &nl_type, type); - if (r < 0) - return r; - - type_get_type_system(nl_type, ret); - return 0; + return type_get_type_system(nl_type); } -int type_system_get_type_system_union(const NLTypeSystem *type_system, const NLTypeSystemUnion **ret, uint16_t type) { +const NLTypeSystemUnion *type_system_get_type_system_union(const NLTypeSystem *type_system, uint16_t type) { const NLType *nl_type; - int r; - assert(ret); + nl_type = type_system_get_type(type_system, type); + if (!nl_type) + return NULL; - r = type_system_get_type(type_system, &nl_type, type); - if (r < 0) - return r; + return type_get_type_system_union(nl_type); +} - type_get_type_system_union(nl_type, ret); - return 0; +NLMatchType type_system_union_get_match_type(const NLTypeSystemUnion *type_system_union) { + assert(type_system_union); + return type_system_union->match_type; } -int type_system_union_get_type_system(const NLTypeSystemUnion *type_system_union, const NLTypeSystem **ret, const char *key) { - int type; +uint16_t type_system_union_get_match_attribute(const NLTypeSystemUnion *type_system_union) { + assert(type_system_union); + assert(type_system_union->match_type == NL_MATCH_SIBLING); + return type_system_union->match_attribute; +} +const NLTypeSystem *type_system_union_get_type_system_by_string(const NLTypeSystemUnion *type_system_union, const char *key) { assert(type_system_union); + assert(type_system_union->elements); assert(type_system_union->match_type == NL_MATCH_SIBLING); - assert(type_system_union->lookup); - assert(type_system_union->type_systems); - assert(ret); assert(key); - type = type_system_union->lookup(key); - if (type < 0) - return -EOPNOTSUPP; - - assert(type < type_system_union->num); - - *ret = &type_system_union->type_systems[type]; + for (size_t i = 0; i < type_system_union->count; i++) + if (streq(type_system_union->elements[i].name, key)) + return &type_system_union->elements[i].type_system; - return 0; + return NULL; } -int type_system_union_protocol_get_type_system(const NLTypeSystemUnion *type_system_union, const NLTypeSystem **ret, uint16_t protocol) { - const NLTypeSystem *type_system; - +const NLTypeSystem *type_system_union_get_type_system_by_protocol(const NLTypeSystemUnion *type_system_union, uint16_t protocol) { assert(type_system_union); - assert(type_system_union->type_systems); + assert(type_system_union->elements); assert(type_system_union->match_type == NL_MATCH_PROTOCOL); - assert(ret); - - if (protocol >= type_system_union->num) - return -EOPNOTSUPP; - type_system = &type_system_union->type_systems[protocol]; - if (!type_system->types) - return -EOPNOTSUPP; - - *ret = type_system; + for (size_t i = 0; i < type_system_union->count; i++) + if (type_system_union->elements[i].protocol == protocol) + return &type_system_union->elements[i].type_system; - return 0; + return NULL; } diff --git a/src/libsystemd/sd-netlink/netlink-types.h b/src/libsystemd/sd-netlink/netlink-types.h index 316d7f1b87..d481f3072f 100644 --- a/src/libsystemd/sd-netlink/netlink-types.h +++ b/src/libsystemd/sd-netlink/netlink-types.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once -#include "macro.h" +#include "sd-netlink.h" enum { NETLINK_TYPE_UNSPEC, @@ -35,105 +35,30 @@ typedef struct NLTypeSystemUnion NLTypeSystemUnion; typedef struct NLTypeSystem NLTypeSystem; typedef struct NLType NLType; -struct NLTypeSystemUnion { - int num; - NLMatchType match_type; - uint16_t match; - int (*lookup)(const char *); - const NLTypeSystem *type_systems; -}; - -extern const NLTypeSystem genl_family_type_system_root; +const NLType *rtnl_get_type(uint16_t nlmsg_type); +const NLType *nfnl_get_type(uint16_t nlmsg_type); +const NLTypeSystem *genl_get_type_system_by_name(const char *name); +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); -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_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); -int type_system_union_get_type_system(const NLTypeSystemUnion *type_system_union, const NLTypeSystem **ret, const char *key); -int type_system_union_protocol_get_type_system(const NLTypeSystemUnion *type_system_union, const NLTypeSystem **ret, uint16_t protocol); - -typedef enum NLUnionLinkInfoData { - NL_UNION_LINK_INFO_DATA_BOND, - NL_UNION_LINK_INFO_DATA_BRIDGE, - NL_UNION_LINK_INFO_DATA_VLAN, - NL_UNION_LINK_INFO_DATA_VETH, - NL_UNION_LINK_INFO_DATA_DUMMY, - NL_UNION_LINK_INFO_DATA_MACVLAN, - NL_UNION_LINK_INFO_DATA_MACVTAP, - NL_UNION_LINK_INFO_DATA_IPVLAN, - NL_UNION_LINK_INFO_DATA_IPVTAP, - NL_UNION_LINK_INFO_DATA_VXLAN, - NL_UNION_LINK_INFO_DATA_IPIP_TUNNEL, - NL_UNION_LINK_INFO_DATA_IPGRE_TUNNEL, - NL_UNION_LINK_INFO_DATA_ERSPAN, - NL_UNION_LINK_INFO_DATA_IPGRETAP_TUNNEL, - NL_UNION_LINK_INFO_DATA_IP6GRE_TUNNEL, - NL_UNION_LINK_INFO_DATA_IP6GRETAP_TUNNEL, - NL_UNION_LINK_INFO_DATA_SIT_TUNNEL, - NL_UNION_LINK_INFO_DATA_VTI_TUNNEL, - NL_UNION_LINK_INFO_DATA_VTI6_TUNNEL, - NL_UNION_LINK_INFO_DATA_IP6TNL_TUNNEL, - NL_UNION_LINK_INFO_DATA_VRF, - NL_UNION_LINK_INFO_DATA_VCAN, - NL_UNION_LINK_INFO_DATA_GENEVE, - NL_UNION_LINK_INFO_DATA_VXCAN, - NL_UNION_LINK_INFO_DATA_WIREGUARD, - NL_UNION_LINK_INFO_DATA_NETDEVSIM, - NL_UNION_LINK_INFO_DATA_CAN, - NL_UNION_LINK_INFO_DATA_MACSEC, - NL_UNION_LINK_INFO_DATA_NLMON, - NL_UNION_LINK_INFO_DATA_XFRM, - NL_UNION_LINK_INFO_DATA_IFB, - NL_UNION_LINK_INFO_DATA_BAREUDP, - NL_UNION_LINK_INFO_DATA_BATADV, - _NL_UNION_LINK_INFO_DATA_MAX, - _NL_UNION_LINK_INFO_DATA_INVALID = -EINVAL, -} NLUnionLinkInfoData; - -const char *nl_union_link_info_data_to_string(NLUnionLinkInfoData p) _const_; -NLUnionLinkInfoData nl_union_link_info_data_from_string(const char *p) _pure_; - -typedef enum NLUnionTCAOptionData { - NL_UNION_TCA_OPTION_DATA_CAKE, - NL_UNION_TCA_OPTION_DATA_CODEL, - NL_UNION_TCA_OPTION_DATA_DRR, - NL_UNION_TCA_OPTION_DATA_ETS, - NL_UNION_TCA_OPTION_DATA_FQ, - NL_UNION_TCA_OPTION_DATA_FQ_CODEL, - NL_UNION_TCA_OPTION_DATA_FQ_PIE, - NL_UNION_TCA_OPTION_DATA_GRED, - NL_UNION_TCA_OPTION_DATA_HHF, - NL_UNION_TCA_OPTION_DATA_HTB, - NL_UNION_TCA_OPTION_DATA_PIE, - NL_UNION_TCA_OPTION_DATA_QFQ, - NL_UNION_TCA_OPTION_DATA_SFB, - NL_UNION_TCA_OPTION_DATA_TBF, - _NL_UNION_TCA_OPTION_DATA_MAX, - _NL_UNION_TCA_OPTION_DATA_INVALID = -EINVAL, -} NLUnionTCAOptionData; - -const char *nl_union_tca_option_data_to_string(NLUnionTCAOptionData p) _const_; -NLUnionTCAOptionData nl_union_tca_option_data_from_string(const char *p) _pure_; +const NLTypeSystem *type_get_type_system(const NLType *type); +const NLTypeSystemUnion *type_get_type_system_union(const NLType *type); -typedef enum NLUnionNFTExprData { - NL_UNION_NFT_EXPR_DATA_BITWISE, - NL_UNION_NFT_EXPR_DATA_CMP, - NL_UNION_NFT_EXPR_DATA_FIB, - NL_UNION_NFT_EXPR_DATA_LOOKUP, - NL_UNION_NFT_EXPR_DATA_PAYLOAD, - NL_UNION_NFT_EXPR_DATA_MASQ, - NL_UNION_NFT_EXPR_DATA_META, - NL_UNION_NFT_EXPR_DATA_NAT, - _NL_UNION_NFT_EXPR_DATA_MAX, - _NL_UNION_NFT_EXPR_DATA_INVALID = -EINVAL, -} NLUnionNFTExprData; +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 char *nl_union_nft_expr_data_to_string(NLUnionNFTExprData p) _const_; -NLUnionNFTExprData nl_union_nft_expr_data_from_string(const char *p) _pure_; +const NLType *type_system_get_type(const NLTypeSystem *type_system, uint16_t type); +const NLTypeSystem *type_system_get_type_system(const NLTypeSystem *type_system, uint16_t type); +const NLTypeSystemUnion *type_system_get_type_system_union(const NLTypeSystem *type_system, uint16_t type); +NLMatchType type_system_union_get_match_type(const NLTypeSystemUnion *type_system_union); +uint16_t type_system_union_get_match_attribute(const NLTypeSystemUnion *type_system_union); +const NLTypeSystem *type_system_union_get_type_system_by_string(const NLTypeSystemUnion *type_system_union, const char *key); +const NLTypeSystem *type_system_union_get_type_system_by_protocol(const NLTypeSystemUnion *type_system_union, uint16_t protocol); diff --git a/src/libsystemd/sd-netlink/netlink-util.c b/src/libsystemd/sd-netlink/netlink-util.c index 1211145fbf..886bb48210 100644 --- a/src/libsystemd/sd-netlink/netlink-util.c +++ b/src/libsystemd/sd-netlink/netlink-util.c @@ -400,25 +400,6 @@ int rtnl_get_link_info(sd_netlink **rtnl, int ifindex, unsigned short *ret_iftyp return 0; } -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(rtnl, ret, NLMSG_ERROR); - if (r < 0) - return r; - - rtnl_message_seal(*ret); - (*ret)->hdr->nlmsg_seq = serial; - - err = NLMSG_DATA((*ret)->hdr); - err->error = error; - - return 0; -} - int rtnl_log_parse_error(int r) { return log_error_errno(r, "Failed to parse netlink message: %m"); } diff --git a/src/libsystemd/sd-netlink/netlink-util.h b/src/libsystemd/sd-netlink/netlink-util.h index a5d725655d..5208dd94e4 100644 --- a/src/libsystemd/sd-netlink/netlink-util.h +++ b/src/libsystemd/sd-netlink/netlink-util.h @@ -29,10 +29,6 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(MultipathRoute*, multipath_route_free); int multipath_route_dup(const MultipathRoute *m, MultipathRoute **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); - static inline bool rtnl_message_type_is_neigh(uint16_t type) { return IN_SET(type, RTM_NEWNEIGH, RTM_GETNEIGH, RTM_DELNEIGH); } diff --git a/src/libsystemd/sd-netlink/sd-netlink.c b/src/libsystemd/sd-netlink/sd-netlink.c index f8a1bde6a6..2d0c940b5a 100644 --- a/src/libsystemd/sd-netlink/sd-netlink.c +++ b/src/libsystemd/sd-netlink/sd-netlink.c @@ -9,27 +9,26 @@ #include "hashmap.h" #include "io-util.h" #include "macro.h" +#include "netlink-genl.h" #include "netlink-internal.h" #include "netlink-slot.h" -#include "netlink-util.h" #include "process-util.h" #include "socket-util.h" #include "string-util.h" -#include "util.h" /* Some really high limit, to catch programming errors */ #define REPLY_CALLBACKS_MAX UINT16_MAX -static int sd_netlink_new(sd_netlink **ret) { - _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; +static int netlink_new(sd_netlink **ret) { + _cleanup_(sd_netlink_unrefp) sd_netlink *nl = NULL; assert_return(ret, -EINVAL); - rtnl = new(sd_netlink, 1); - if (!rtnl) + nl = new(sd_netlink, 1); + if (!nl) return -ENOMEM; - *rtnl = (sd_netlink) { + *nl = (sd_netlink) { .n_ref = 1, .fd = -1, .sockaddr.nl.nl_family = AF_NETLINK, @@ -61,60 +60,48 @@ static int sd_netlink_new(sd_netlink **ret) { .serial = (uint32_t) (now(CLOCK_MONOTONIC) % UINT32_MAX) + 1, }; - /* We guarantee that the read buffer has at least space for - * a message header */ - if (!greedy_realloc((void**)&rtnl->rbuffer, sizeof(struct nlmsghdr), sizeof(uint8_t))) + /* We guarantee that the read buffer has at least space for a message header */ + if (!greedy_realloc((void**) &nl->rbuffer, sizeof(struct nlmsghdr), sizeof(uint8_t))) return -ENOMEM; - *ret = TAKE_PTR(rtnl); - + *ret = TAKE_PTR(nl); return 0; } -int sd_netlink_new_from_netlink(sd_netlink **ret, int fd) { - _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; +int sd_netlink_new_from_fd(sd_netlink **ret, int fd) { + _cleanup_(sd_netlink_unrefp) sd_netlink *nl = NULL; socklen_t addrlen; int r; assert_return(ret, -EINVAL); - r = sd_netlink_new(&rtnl); + r = netlink_new(&nl); if (r < 0) return r; - addrlen = sizeof(rtnl->sockaddr); + addrlen = sizeof(nl->sockaddr); - r = getsockname(fd, &rtnl->sockaddr.sa, &addrlen); + r = getsockname(fd, &nl->sockaddr.sa, &addrlen); if (r < 0) return -errno; - if (rtnl->sockaddr.nl.nl_family != AF_NETLINK) + if (nl->sockaddr.nl.nl_family != AF_NETLINK) return -EINVAL; - rtnl->fd = fd; - - *ret = TAKE_PTR(rtnl); + nl->fd = fd; + *ret = TAKE_PTR(nl); return 0; } -static bool rtnl_pid_changed(const sd_netlink *rtnl) { - assert(rtnl); - - /* We don't support people creating an rtnl connection and - * keeping it around over a fork(). Let's complain. */ - - return rtnl->original_pid != getpid_cached(); -} - int sd_netlink_open_fd(sd_netlink **ret, int fd) { - _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; + _cleanup_(sd_netlink_unrefp) sd_netlink *nl = NULL; int r, protocol; assert_return(ret, -EINVAL); assert_return(fd >= 0, -EBADF); - r = sd_netlink_new(&rtnl); + r = netlink_new(&nl); if (r < 0) return r; @@ -122,8 +109,8 @@ int sd_netlink_open_fd(sd_netlink **ret, int fd) { if (r < 0) return r; - rtnl->fd = fd; - rtnl->protocol = protocol; + nl->fd = fd; + nl->protocol = protocol; r = setsockopt_int(fd, SOL_NETLINK, NETLINK_EXT_ACK, true); if (r < 0) @@ -133,14 +120,14 @@ int sd_netlink_open_fd(sd_netlink **ret, int fd) { if (r < 0) log_debug_errno(r, "sd-netlink: Failed to enable NETLINK_GET_STRICT_CHK option, ignoring: %m"); - r = socket_bind(rtnl); + r = socket_bind(nl); if (r < 0) { - rtnl->fd = -1; /* on failure, the caller remains owner of the fd, hence don't close it here */ - rtnl->protocol = -1; + nl->fd = -1; /* on failure, the caller remains owner of the fd, hence don't close it here */ + nl->protocol = -1; return r; } - *ret = TAKE_PTR(rtnl); + *ret = TAKE_PTR(nl); return 0; } @@ -165,91 +152,101 @@ 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); +bool netlink_pid_changed(sd_netlink *nl) { + assert(nl); - return fd_inc_rcvbuf(rtnl->fd, size); + /* We don't support people creating an nl connection and + * keeping it around over a fork(). Let's complain. */ + + return nl->original_pid != getpid_cached(); } -static sd_netlink *netlink_free(sd_netlink *rtnl) { +int sd_netlink_inc_rcvbuf(sd_netlink *nl, size_t size) { + assert_return(nl, -EINVAL); + assert_return(!netlink_pid_changed(nl), -ECHILD); + + return fd_inc_rcvbuf(nl->fd, size); +} + +static sd_netlink *netlink_free(sd_netlink *nl) { sd_netlink_slot *s; unsigned i; - assert(rtnl); + assert(nl); - for (i = 0; i < rtnl->rqueue_size; i++) - sd_netlink_message_unref(rtnl->rqueue[i]); - free(rtnl->rqueue); + for (i = 0; i < nl->rqueue_size; i++) + sd_netlink_message_unref(nl->rqueue[i]); + free(nl->rqueue); - for (i = 0; i < rtnl->rqueue_partial_size; i++) - sd_netlink_message_unref(rtnl->rqueue_partial[i]); - free(rtnl->rqueue_partial); + for (i = 0; i < nl->rqueue_partial_size; i++) + sd_netlink_message_unref(nl->rqueue_partial[i]); + free(nl->rqueue_partial); - free(rtnl->rbuffer); + free(nl->rbuffer); - while ((s = rtnl->slots)) { + while ((s = nl->slots)) { assert(s->floating); netlink_slot_disconnect(s, true); } - hashmap_free(rtnl->reply_callbacks); - prioq_free(rtnl->reply_callbacks_prioq); + hashmap_free(nl->reply_callbacks); + prioq_free(nl->reply_callbacks_prioq); - sd_event_source_unref(rtnl->io_event_source); - sd_event_source_unref(rtnl->time_event_source); - sd_event_unref(rtnl->event); + sd_event_source_unref(nl->io_event_source); + sd_event_source_unref(nl->time_event_source); + sd_event_unref(nl->event); - hashmap_free(rtnl->broadcast_group_refs); + hashmap_free(nl->broadcast_group_refs); - hashmap_free(rtnl->genl_family_to_nlmsg_type); - hashmap_free(rtnl->nlmsg_type_to_genl_family); + genl_clear_family(nl); - safe_close(rtnl->fd); - return mfree(rtnl); + safe_close(nl->fd); + return mfree(nl); } DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_netlink, sd_netlink, netlink_free); -static void rtnl_seal_message(sd_netlink *rtnl, sd_netlink_message *m) { +static void netlink_seal_message(sd_netlink *nl, sd_netlink_message *m) { uint32_t picked; - assert(rtnl); - assert(!rtnl_pid_changed(rtnl)); + assert(nl); + assert(!netlink_pid_changed(nl)); assert(m); assert(m->hdr); /* Avoid collisions with outstanding requests */ do { - picked = rtnl->serial; + picked = nl->serial; /* Don't use seq == 0, as that is used for broadcasts, so we would get confused by replies to such messages */ - rtnl->serial = rtnl->serial == UINT32_MAX ? 1 : rtnl->serial + 1; + nl->serial = nl->serial == UINT32_MAX ? 1 : nl->serial + 1; - } while (hashmap_contains(rtnl->reply_callbacks, UINT32_TO_PTR(picked))); + } while (hashmap_contains(nl->reply_callbacks, UINT32_TO_PTR(picked))); m->hdr->nlmsg_seq = picked; - rtnl_message_seal(m); + message_seal(m); } -int sd_netlink_send(sd_netlink *nl, - sd_netlink_message *message, - uint32_t *serial) { +int sd_netlink_send( + sd_netlink *nl, + sd_netlink_message *message, + uint32_t *serial) { + int r; assert_return(nl, -EINVAL); - assert_return(!rtnl_pid_changed(nl), -ECHILD); + assert_return(!netlink_pid_changed(nl), -ECHILD); assert_return(message, -EINVAL); assert_return(!message->sealed, -EPERM); - rtnl_seal_message(nl, message); + netlink_seal_message(nl, message); r = socket_write_message(nl, message); if (r < 0) return r; if (serial) - *serial = rtnl_message_get_serial(message); + *serial = message_get_serial(message); return 1; } @@ -264,7 +261,7 @@ int sd_netlink_sendv( int r; assert_return(nl, -EINVAL); - assert_return(!rtnl_pid_changed(nl), -ECHILD); + assert_return(!netlink_pid_changed(nl), -ECHILD); assert_return(messages, -EINVAL); assert_return(msgcount > 0, -EINVAL); @@ -277,9 +274,9 @@ int sd_netlink_sendv( for (unsigned i = 0; i < msgcount; i++) { assert_return(!messages[i]->sealed, -EPERM); - rtnl_seal_message(nl, messages[i]); + netlink_seal_message(nl, messages[i]); if (serials) - serials[i] = rtnl_message_get_serial(messages[i]); + serials[i] = message_get_serial(messages[i]); } r = socket_writev_message(nl, messages, msgcount); @@ -292,45 +289,45 @@ int sd_netlink_sendv( return r; } -int rtnl_rqueue_make_room(sd_netlink *rtnl) { - assert(rtnl); +int netlink_rqueue_make_room(sd_netlink *nl) { + assert(nl); - if (rtnl->rqueue_size >= RTNL_RQUEUE_MAX) + if (nl->rqueue_size >= NETLINK_RQUEUE_MAX) return log_debug_errno(SYNTHETIC_ERRNO(ENOBUFS), - "rtnl: exhausted the read queue size (%d)", - RTNL_RQUEUE_MAX); + "sd-netlink: exhausted the read queue size (%d)", + NETLINK_RQUEUE_MAX); - if (!GREEDY_REALLOC(rtnl->rqueue, rtnl->rqueue_size + 1)) + if (!GREEDY_REALLOC(nl->rqueue, nl->rqueue_size + 1)) return -ENOMEM; return 0; } -int rtnl_rqueue_partial_make_room(sd_netlink *rtnl) { - assert(rtnl); +int netlink_rqueue_partial_make_room(sd_netlink *nl) { + assert(nl); - if (rtnl->rqueue_partial_size >= RTNL_RQUEUE_MAX) + if (nl->rqueue_partial_size >= NETLINK_RQUEUE_MAX) return log_debug_errno(SYNTHETIC_ERRNO(ENOBUFS), - "rtnl: exhausted the partial read queue size (%d)", - RTNL_RQUEUE_MAX); + "sd-netlink: exhausted the partial read queue size (%d)", + NETLINK_RQUEUE_MAX); - if (!GREEDY_REALLOC(rtnl->rqueue_partial, rtnl->rqueue_partial_size + 1)) + if (!GREEDY_REALLOC(nl->rqueue_partial, nl->rqueue_partial_size + 1)) return -ENOMEM; return 0; } -static int dispatch_rqueue(sd_netlink *rtnl, sd_netlink_message **message) { +static int dispatch_rqueue(sd_netlink *nl, sd_netlink_message **message) { int r; - assert(rtnl); + assert(nl); assert(message); - if (rtnl->rqueue_size <= 0) { + if (nl->rqueue_size <= 0) { /* Try to read a new message */ - r = socket_read_message(rtnl); + r = socket_read_message(nl); if (r == -ENOBUFS) { /* FIXME: ignore buffer overruns for now */ - log_debug_errno(r, "Got ENOBUFS from netlink socket, ignoring."); + log_debug_errno(r, "sd-netlink: Got ENOBUFS from netlink socket, ignoring."); return 1; } if (r <= 0) @@ -338,23 +335,23 @@ static int dispatch_rqueue(sd_netlink *rtnl, sd_netlink_message **message) { } /* Dispatch a queued message */ - *message = rtnl->rqueue[0]; - rtnl->rqueue_size--; - memmove(rtnl->rqueue, rtnl->rqueue + 1, sizeof(sd_netlink_message*) * rtnl->rqueue_size); + *message = nl->rqueue[0]; + nl->rqueue_size--; + memmove(nl->rqueue, nl->rqueue + 1, sizeof(sd_netlink_message*) * nl->rqueue_size); return 1; } -static int process_timeout(sd_netlink *rtnl) { +static int process_timeout(sd_netlink *nl) { _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; struct reply_callback *c; sd_netlink_slot *slot; usec_t n; int r; - assert(rtnl); + assert(nl); - c = prioq_peek(rtnl->reply_callbacks_prioq); + c = prioq_peek(nl->reply_callbacks_prioq); if (!c) return 0; @@ -362,17 +359,17 @@ static int process_timeout(sd_netlink *rtnl) { if (c->timeout > n) return 0; - r = rtnl_message_new_synthetic_error(rtnl, -ETIMEDOUT, c->serial, &m); + r = message_new_synthetic_error(nl, -ETIMEDOUT, c->serial, &m); if (r < 0) return r; - assert_se(prioq_pop(rtnl->reply_callbacks_prioq) == c); + assert_se(prioq_pop(nl->reply_callbacks_prioq) == c); c->timeout = 0; - hashmap_remove(rtnl->reply_callbacks, UINT32_TO_PTR(c->serial)); + hashmap_remove(nl->reply_callbacks, UINT32_TO_PTR(c->serial)); slot = container_of(c, sd_netlink_slot, reply_callback); - r = c->callback(rtnl, m, slot->userdata); + r = c->callback(nl, m, slot->userdata); if (r < 0) log_debug_errno(r, "sd-netlink: timedout callback %s%s%sfailed: %m", slot->description ? "'" : "", @@ -385,23 +382,23 @@ static int process_timeout(sd_netlink *rtnl) { return 1; } -static int process_reply(sd_netlink *rtnl, sd_netlink_message *m) { +static int process_reply(sd_netlink *nl, sd_netlink_message *m) { struct reply_callback *c; sd_netlink_slot *slot; uint32_t serial; uint16_t type; int r; - assert(rtnl); + assert(nl); assert(m); - serial = rtnl_message_get_serial(m); - c = hashmap_remove(rtnl->reply_callbacks, UINT32_TO_PTR(serial)); + serial = message_get_serial(m); + c = hashmap_remove(nl->reply_callbacks, UINT32_TO_PTR(serial)); if (!c) return 0; if (c->timeout != 0) { - prioq_remove(rtnl->reply_callbacks_prioq, c, &c->prioq_idx); + prioq_remove(nl->reply_callbacks_prioq, c, &c->prioq_idx); c->timeout = 0; } @@ -414,7 +411,7 @@ static int process_reply(sd_netlink *rtnl, sd_netlink_message *m) { slot = container_of(c, sd_netlink_slot, reply_callback); - r = c->callback(rtnl, m, slot->userdata); + r = c->callback(nl, m, slot->userdata); if (r < 0) log_debug_errno(r, "sd-netlink: reply callback %s%s%sfailed: %m", slot->description ? "'" : "", @@ -427,26 +424,37 @@ static int process_reply(sd_netlink *rtnl, sd_netlink_message *m) { return 1; } -static int process_match(sd_netlink *rtnl, sd_netlink_message *m) { +static int process_match(sd_netlink *nl, sd_netlink_message *m) { struct match_callback *c; - sd_netlink_slot *slot; uint16_t type; + uint8_t cmd; int r; - assert(rtnl); + assert(nl); assert(m); r = sd_netlink_message_get_type(m, &type); if (r < 0) return r; - LIST_FOREACH(match_callbacks, c, rtnl->match_callbacks) { - if (type != c->type) + if (m->protocol == NETLINK_GENERIC) { + r = sd_genl_message_get_command(nl, m, &cmd); + if (r < 0) + return r; + } else + cmd = 0; + + LIST_FOREACH(match_callbacks, c, nl->match_callbacks) { + sd_netlink_slot *slot; + + if (c->type != type) + continue; + if (c->cmd != 0 && c->cmd != cmd) continue; slot = container_of(c, sd_netlink_slot, match_callback); - r = c->callback(rtnl, m, slot->userdata); + r = c->callback(nl, m, slot->userdata); if (r < 0) log_debug_errno(r, "sd-netlink: match callback %s%s%sfailed: %m", slot->description ? "'" : "", @@ -459,28 +467,28 @@ static int process_match(sd_netlink *rtnl, sd_netlink_message *m) { return 1; } -static int process_running(sd_netlink *rtnl, sd_netlink_message **ret) { +static int process_running(sd_netlink *nl, sd_netlink_message **ret) { _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; int r; - assert(rtnl); + assert(nl); - r = process_timeout(rtnl); + r = process_timeout(nl); if (r != 0) goto null_message; - r = dispatch_rqueue(rtnl, &m); + r = dispatch_rqueue(nl, &m); if (r < 0) return r; if (!m) goto null_message; if (sd_netlink_message_is_broadcast(m)) { - r = process_match(rtnl, m); + r = process_match(nl, m); if (r != 0) goto null_message; } else { - r = process_reply(rtnl, m); + r = process_reply(nl, m); if (r != 0) goto null_message; } @@ -500,17 +508,17 @@ null_message: return r; } -int sd_netlink_process(sd_netlink *rtnl, sd_netlink_message **ret) { - NETLINK_DONT_DESTROY(rtnl); +int sd_netlink_process(sd_netlink *nl, sd_netlink_message **ret) { + NETLINK_DONT_DESTROY(nl); int r; - assert_return(rtnl, -EINVAL); - assert_return(!rtnl_pid_changed(rtnl), -ECHILD); - assert_return(!rtnl->processing, -EBUSY); + assert_return(nl, -EINVAL); + assert_return(!netlink_pid_changed(nl), -ECHILD); + assert_return(!nl->processing, -EBUSY); - rtnl->processing = true; - r = process_running(rtnl, ret); - rtnl->processing = false; + nl->processing = true; + r = process_running(nl, ret); + nl->processing = false; return r; } @@ -520,18 +528,18 @@ static usec_t calc_elapse(uint64_t usec) { return 0; if (usec == 0) - usec = RTNL_DEFAULT_TIMEOUT; + usec = NETLINK_DEFAULT_TIMEOUT_USEC; return usec_add(now(CLOCK_MONOTONIC), usec); } -static int rtnl_poll(sd_netlink *rtnl, bool need_more, usec_t timeout_usec) { +static int netlink_poll(sd_netlink *nl, bool need_more, usec_t timeout_usec) { usec_t m = USEC_INFINITY; int r, e; - assert(rtnl); + assert(nl); - e = sd_netlink_get_events(rtnl); + e = sd_netlink_get_events(nl); if (e < 0) return e; @@ -545,14 +553,14 @@ static int rtnl_poll(sd_netlink *rtnl, bool need_more, usec_t timeout_usec) { /* Caller wants to process if there is something to * process, but doesn't care otherwise */ - r = sd_netlink_get_timeout(rtnl, &until); + r = sd_netlink_get_timeout(nl, &until); if (r < 0) return r; m = usec_sub_unsigned(until, now(CLOCK_MONOTONIC)); } - r = fd_wait_for_event(rtnl->fd, e, MIN(m, timeout_usec)); + r = fd_wait_for_event(nl->fd, e, MIN(m, timeout_usec)); if (r <= 0) return r; @@ -561,12 +569,12 @@ static int rtnl_poll(sd_netlink *rtnl, bool need_more, usec_t timeout_usec) { int sd_netlink_wait(sd_netlink *nl, uint64_t timeout_usec) { assert_return(nl, -EINVAL); - assert_return(!rtnl_pid_changed(nl), -ECHILD); + assert_return(!netlink_pid_changed(nl), -ECHILD); if (nl->rqueue_size > 0) return 0; - return rtnl_poll(nl, false, timeout_usec); + return netlink_poll(nl, false, timeout_usec); } static int timeout_compare(const void *a, const void *b) { @@ -597,7 +605,7 @@ int sd_netlink_call_async( assert_return(nl, -EINVAL); assert_return(m, -EINVAL); assert_return(callback, -EINVAL); - assert_return(!rtnl_pid_changed(nl), -ECHILD); + assert_return(!netlink_pid_changed(nl), -ECHILD); if (hashmap_size(nl->reply_callbacks) >= REPLY_CALLBACKS_MAX) return -ERANGE; @@ -647,7 +655,7 @@ int sd_netlink_call_async( } int sd_netlink_read( - sd_netlink *rtnl, + sd_netlink *nl, uint32_t serial, uint64_t usec, sd_netlink_message **ret) { @@ -655,29 +663,29 @@ int sd_netlink_read( usec_t timeout; int r; - assert_return(rtnl, -EINVAL); - assert_return(!rtnl_pid_changed(rtnl), -ECHILD); + assert_return(nl, -EINVAL); + assert_return(!netlink_pid_changed(nl), -ECHILD); timeout = calc_elapse(usec); for (;;) { usec_t left; - for (unsigned i = 0; i < rtnl->rqueue_size; i++) { + for (unsigned i = 0; i < nl->rqueue_size; i++) { _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *incoming = NULL; uint32_t received_serial; uint16_t type; - received_serial = rtnl_message_get_serial(rtnl->rqueue[i]); + received_serial = message_get_serial(nl->rqueue[i]); if (received_serial != serial) continue; - incoming = rtnl->rqueue[i]; + incoming = nl->rqueue[i]; /* found a match, remove from rqueue and return it */ - memmove(rtnl->rqueue + i,rtnl->rqueue + i + 1, - sizeof(sd_netlink_message*) * (rtnl->rqueue_size - i - 1)); - rtnl->rqueue_size--; + memmove(nl->rqueue + i, nl->rqueue + i + 1, + sizeof(sd_netlink_message*) * (nl->rqueue_size - i - 1)); + nl->rqueue_size--; r = sd_netlink_message_get_errno(incoming); if (r < 0) @@ -697,7 +705,7 @@ int sd_netlink_read( return 1; } - r = socket_read_message(rtnl); + r = socket_read_message(nl); if (r < 0) return r; if (r > 0) @@ -715,7 +723,7 @@ int sd_netlink_read( } else left = USEC_INFINITY; - r = rtnl_poll(rtnl, true, left); + r = netlink_poll(nl, true, left); if (r < 0) return r; if (r == 0) @@ -724,7 +732,7 @@ int sd_netlink_read( } int sd_netlink_call( - sd_netlink *rtnl, + sd_netlink *nl, sd_netlink_message *message, uint64_t usec, sd_netlink_message **ret) { @@ -732,37 +740,37 @@ int sd_netlink_call( uint32_t serial; int r; - assert_return(rtnl, -EINVAL); - assert_return(!rtnl_pid_changed(rtnl), -ECHILD); + assert_return(nl, -EINVAL); + assert_return(!netlink_pid_changed(nl), -ECHILD); assert_return(message, -EINVAL); - r = sd_netlink_send(rtnl, message, &serial); + r = sd_netlink_send(nl, message, &serial); if (r < 0) return r; - return sd_netlink_read(rtnl, serial, usec, ret); + return sd_netlink_read(nl, serial, usec, ret); } -int sd_netlink_get_events(sd_netlink *rtnl) { - assert_return(rtnl, -EINVAL); - assert_return(!rtnl_pid_changed(rtnl), -ECHILD); +int sd_netlink_get_events(sd_netlink *nl) { + assert_return(nl, -EINVAL); + assert_return(!netlink_pid_changed(nl), -ECHILD); - return rtnl->rqueue_size == 0 ? POLLIN : 0; + return nl->rqueue_size == 0 ? POLLIN : 0; } -int sd_netlink_get_timeout(sd_netlink *rtnl, uint64_t *timeout_usec) { +int sd_netlink_get_timeout(sd_netlink *nl, uint64_t *timeout_usec) { struct reply_callback *c; - assert_return(rtnl, -EINVAL); + assert_return(nl, -EINVAL); assert_return(timeout_usec, -EINVAL); - assert_return(!rtnl_pid_changed(rtnl), -ECHILD); + assert_return(!netlink_pid_changed(nl), -ECHILD); - if (rtnl->rqueue_size > 0) { + if (nl->rqueue_size > 0) { *timeout_usec = 0; return 1; } - c = prioq_peek(rtnl->reply_callbacks_prioq); + c = prioq_peek(nl->reply_callbacks_prioq); if (!c) { *timeout_usec = UINT64_MAX; return 0; @@ -774,12 +782,12 @@ int sd_netlink_get_timeout(sd_netlink *rtnl, uint64_t *timeout_usec) { } static int io_callback(sd_event_source *s, int fd, uint32_t revents, void *userdata) { - sd_netlink *rtnl = userdata; + sd_netlink *nl = userdata; int r; - assert(rtnl); + assert(nl); - r = sd_netlink_process(rtnl, NULL); + r = sd_netlink_process(nl, NULL); if (r < 0) return r; @@ -787,12 +795,12 @@ static int io_callback(sd_event_source *s, int fd, uint32_t revents, void *userd } static int time_callback(sd_event_source *s, uint64_t usec, void *userdata) { - sd_netlink *rtnl = userdata; + sd_netlink *nl = userdata; int r; - assert(rtnl); + assert(nl); - r = sd_netlink_process(rtnl, NULL); + r = sd_netlink_process(nl, NULL); if (r < 0) return r; @@ -800,192 +808,212 @@ static int time_callback(sd_event_source *s, uint64_t usec, void *userdata) { } static int prepare_callback(sd_event_source *s, void *userdata) { - sd_netlink *rtnl = userdata; + sd_netlink *nl = userdata; int r, e; usec_t until; assert(s); - assert(rtnl); + assert(nl); - e = sd_netlink_get_events(rtnl); + e = sd_netlink_get_events(nl); if (e < 0) return e; - r = sd_event_source_set_io_events(rtnl->io_event_source, e); + r = sd_event_source_set_io_events(nl->io_event_source, e); if (r < 0) return r; - r = sd_netlink_get_timeout(rtnl, &until); + r = sd_netlink_get_timeout(nl, &until); if (r < 0) return r; if (r > 0) { int j; - j = sd_event_source_set_time(rtnl->time_event_source, until); + j = sd_event_source_set_time(nl->time_event_source, until); if (j < 0) return j; } - r = sd_event_source_set_enabled(rtnl->time_event_source, r > 0); + r = sd_event_source_set_enabled(nl->time_event_source, r > 0); if (r < 0) return r; return 1; } -int sd_netlink_attach_event(sd_netlink *rtnl, sd_event *event, int64_t priority) { +int sd_netlink_attach_event(sd_netlink *nl, sd_event *event, int64_t priority) { int r; - assert_return(rtnl, -EINVAL); - assert_return(!rtnl->event, -EBUSY); + assert_return(nl, -EINVAL); + assert_return(!nl->event, -EBUSY); - assert(!rtnl->io_event_source); - assert(!rtnl->time_event_source); + assert(!nl->io_event_source); + assert(!nl->time_event_source); if (event) - rtnl->event = sd_event_ref(event); + nl->event = sd_event_ref(event); else { - r = sd_event_default(&rtnl->event); + r = sd_event_default(&nl->event); if (r < 0) return r; } - r = sd_event_add_io(rtnl->event, &rtnl->io_event_source, rtnl->fd, 0, io_callback, rtnl); + r = sd_event_add_io(nl->event, &nl->io_event_source, nl->fd, 0, io_callback, nl); if (r < 0) goto fail; - r = sd_event_source_set_priority(rtnl->io_event_source, priority); + r = sd_event_source_set_priority(nl->io_event_source, priority); if (r < 0) goto fail; - r = sd_event_source_set_description(rtnl->io_event_source, "rtnl-receive-message"); + r = sd_event_source_set_description(nl->io_event_source, "netlink-receive-message"); if (r < 0) goto fail; - r = sd_event_source_set_prepare(rtnl->io_event_source, prepare_callback); + r = sd_event_source_set_prepare(nl->io_event_source, prepare_callback); if (r < 0) goto fail; - r = sd_event_add_time(rtnl->event, &rtnl->time_event_source, CLOCK_MONOTONIC, 0, 0, time_callback, rtnl); + r = sd_event_add_time(nl->event, &nl->time_event_source, CLOCK_MONOTONIC, 0, 0, time_callback, nl); if (r < 0) goto fail; - r = sd_event_source_set_priority(rtnl->time_event_source, priority); + r = sd_event_source_set_priority(nl->time_event_source, priority); if (r < 0) goto fail; - r = sd_event_source_set_description(rtnl->time_event_source, "rtnl-timer"); + r = sd_event_source_set_description(nl->time_event_source, "netlink-timer"); if (r < 0) goto fail; return 0; fail: - sd_netlink_detach_event(rtnl); + sd_netlink_detach_event(nl); return r; } -int sd_netlink_detach_event(sd_netlink *rtnl) { - assert_return(rtnl, -EINVAL); - assert_return(rtnl->event, -ENXIO); +int sd_netlink_detach_event(sd_netlink *nl) { + assert_return(nl, -EINVAL); + assert_return(nl->event, -ENXIO); - rtnl->io_event_source = sd_event_source_unref(rtnl->io_event_source); + nl->io_event_source = sd_event_source_unref(nl->io_event_source); - rtnl->time_event_source = sd_event_source_unref(rtnl->time_event_source); + nl->time_event_source = sd_event_source_unref(nl->time_event_source); - rtnl->event = sd_event_unref(rtnl->event); + nl->event = sd_event_unref(nl->event); return 0; } -int sd_netlink_add_match( - sd_netlink *rtnl, +int netlink_add_match_internal( + sd_netlink *nl, sd_netlink_slot **ret_slot, + const uint32_t *groups, + size_t n_groups, uint16_t type, + uint8_t cmd, sd_netlink_message_handler_t callback, sd_netlink_destroy_t destroy_callback, void *userdata, const char *description) { + _cleanup_free_ sd_netlink_slot *slot = NULL; int r; - assert_return(rtnl, -EINVAL); - assert_return(callback, -EINVAL); - assert_return(!rtnl_pid_changed(rtnl), -ECHILD); + assert(groups); + assert(n_groups > 0); + + for (size_t i = 0; i < n_groups; i++) { + r = socket_broadcast_group_ref(nl, groups[i]); + if (r < 0) + return r; + } - r = netlink_slot_allocate(rtnl, !ret_slot, NETLINK_MATCH_CALLBACK, sizeof(struct match_callback), userdata, description, &slot); + r = netlink_slot_allocate(nl, !ret_slot, NETLINK_MATCH_CALLBACK, sizeof(struct match_callback), + userdata, description, &slot); if (r < 0) return r; + slot->match_callback.groups = newdup(uint32_t, groups, n_groups); + if (!slot->match_callback.groups) + return -ENOMEM; + + slot->match_callback.n_groups = n_groups; slot->match_callback.callback = callback; slot->match_callback.type = type; + slot->match_callback.cmd = cmd; + + LIST_PREPEND(match_callbacks, nl->match_callbacks, &slot->match_callback); + + /* Set this at last. Otherwise, some failures in above call the destroy callback but some do not. */ + slot->destroy_callback = destroy_callback; + + if (ret_slot) + *ret_slot = slot; + + TAKE_PTR(slot); + return 0; +} + +int sd_netlink_add_match( + sd_netlink *rtnl, + sd_netlink_slot **ret_slot, + uint16_t type, + sd_netlink_message_handler_t callback, + sd_netlink_destroy_t destroy_callback, + void *userdata, + const char *description) { + + static const uint32_t + address_groups[] = { RTNLGRP_IPV4_IFADDR, RTNLGRP_IPV6_IFADDR, }, + link_groups[] = { RTNLGRP_LINK, }, + neighbor_groups[] = { RTNLGRP_NEIGH, }, + nexthop_groups[] = { RTNLGRP_NEXTHOP, }, + route_groups[] = { RTNLGRP_IPV4_ROUTE, RTNLGRP_IPV6_ROUTE, }, + rule_groups[] = { RTNLGRP_IPV4_RULE, RTNLGRP_IPV6_RULE, }; + const uint32_t *groups; + size_t n_groups; + + assert_return(rtnl, -EINVAL); + assert_return(callback, -EINVAL); + assert_return(!netlink_pid_changed(rtnl), -ECHILD); switch (type) { case RTM_NEWLINK: case RTM_DELLINK: - r = socket_broadcast_group_ref(rtnl, RTNLGRP_LINK); - if (r < 0) - return r; - + groups = link_groups; + n_groups = ELEMENTSOF(link_groups); break; case RTM_NEWADDR: case RTM_DELADDR: - r = socket_broadcast_group_ref(rtnl, RTNLGRP_IPV4_IFADDR); - if (r < 0) - return r; - - r = socket_broadcast_group_ref(rtnl, RTNLGRP_IPV6_IFADDR); - if (r < 0) - return r; - + groups = address_groups; + n_groups = ELEMENTSOF(address_groups); break; case RTM_NEWNEIGH: case RTM_DELNEIGH: - r = socket_broadcast_group_ref(rtnl, RTNLGRP_NEIGH); - if (r < 0) - return r; - + groups = neighbor_groups; + n_groups = ELEMENTSOF(neighbor_groups); break; case RTM_NEWROUTE: case RTM_DELROUTE: - r = socket_broadcast_group_ref(rtnl, RTNLGRP_IPV4_ROUTE); - if (r < 0) - return r; - - r = socket_broadcast_group_ref(rtnl, RTNLGRP_IPV6_ROUTE); - if (r < 0) - return r; + groups = route_groups; + n_groups = ELEMENTSOF(route_groups); break; case RTM_NEWRULE: case RTM_DELRULE: - r = socket_broadcast_group_ref(rtnl, RTNLGRP_IPV4_RULE); - if (r < 0) - return r; - - r = socket_broadcast_group_ref(rtnl, RTNLGRP_IPV6_RULE); - if (r < 0) - return r; + groups = rule_groups; + n_groups = ELEMENTSOF(rule_groups); break; case RTM_NEWNEXTHOP: case RTM_DELNEXTHOP: - r = socket_broadcast_group_ref(rtnl, RTNLGRP_NEXTHOP); - if (r < 0) - return r; - break; - + groups = nexthop_groups; + n_groups = ELEMENTSOF(nexthop_groups); + break; default: return -EOPNOTSUPP; } - LIST_PREPEND(match_callbacks, rtnl->match_callbacks, &slot->match_callback); - - /* Set this at last. Otherwise, some failures in above call the destroy callback but some do not. */ - slot->destroy_callback = destroy_callback; - - if (ret_slot) - *ret_slot = slot; - - TAKE_PTR(slot); - - return 0; + return netlink_add_match_internal(rtnl, ret_slot, groups, n_groups, type, 0, callback, + destroy_callback, userdata, description); } diff --git a/src/libsystemd/sd-netlink/test-netlink.c b/src/libsystemd/sd-netlink/test-netlink.c index 41a7280477..c5a5e512a2 100644 --- a/src/libsystemd/sd-netlink/test-netlink.c +++ b/src/libsystemd/sd-netlink/test-netlink.c @@ -2,31 +2,40 @@ #include <net/if.h> #include <netinet/ether.h> +#include <netinet/in.h> +#include <linux/fou.h> #include <linux/genetlink.h> +#include <linux/if_macsec.h> +#include <linux/l2tp.h> +#include <linux/nl80211.h> #include "sd-netlink.h" #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" #include "stdio-util.h" #include "string-util.h" #include "strv.h" -#include "util.h" +#include "tests.h" static void test_message_link_bridge(sd_netlink *rtnl) { _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *message = NULL; uint32_t cost; + log_debug("/* %s */", __func__); + assert_se(sd_rtnl_message_new_link(rtnl, &message, RTM_NEWLINK, 1) >= 0); assert_se(sd_rtnl_message_link_set_family(message, AF_BRIDGE) >= 0); assert_se(sd_netlink_message_open_container(message, IFLA_PROTINFO) >= 0); assert_se(sd_netlink_message_append_u32(message, IFLA_BRPORT_COST, 10) >= 0); assert_se(sd_netlink_message_close_container(message) >= 0); - assert_se(sd_netlink_message_rewind(message, NULL) >= 0); + assert_se(sd_netlink_message_rewind(message, rtnl) >= 0); assert_se(sd_netlink_message_enter_container(message, IFLA_PROTINFO) >= 0); assert_se(sd_netlink_message_read_u32(message, IFLA_BRPORT_COST, &cost) >= 0); @@ -40,6 +49,8 @@ static void test_link_configure(sd_netlink *rtnl, int ifindex) { const char *name_out; struct ether_addr mac_out; + log_debug("/* %s */", __func__); + /* we'd really like to test NEWLINK, but let's not mess with the running kernel */ assert_se(sd_rtnl_message_new_link(rtnl, &message, RTM_GETLINK, ifindex) >= 0); @@ -57,6 +68,8 @@ static void test_link_get(sd_netlink *rtnl, int ifindex) { uint32_t u32_data; struct ether_addr eth_data; + log_debug("/* %s */", __func__); + assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_GETLINK, ifindex) >= 0); assert_se(m); @@ -83,6 +96,8 @@ static void test_address_get(sd_netlink *rtnl, int ifindex) { struct ifa_cacheinfo cache; const char *label; + log_debug("/* %s */", __func__); + assert_se(sd_rtnl_message_new_addr(rtnl, &m, RTM_GETADDR, ifindex, AF_INET) >= 0); assert_se(m); assert_se(sd_netlink_message_request_dump(m, true) >= 0); @@ -100,6 +115,8 @@ static void test_route(sd_netlink *rtnl) { uint32_t index = 2, u32_data; int r; + log_debug("/* %s */", __func__); + 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"); @@ -120,7 +137,7 @@ static void test_route(sd_netlink *rtnl) { return; } - assert_se(sd_netlink_message_rewind(req, NULL) >= 0); + assert_se(sd_netlink_message_rewind(req, rtnl) >= 0); assert_se(sd_netlink_message_read_in_addr(req, RTA_GATEWAY, &addr_data) >= 0); assert_se(addr_data.s_addr == addr.s_addr); @@ -134,6 +151,8 @@ static void test_route(sd_netlink *rtnl) { static void test_multiple(void) { sd_netlink *rtnl1, *rtnl2; + log_debug("/* %s */", __func__); + assert_se(sd_netlink_open(&rtnl1) >= 0); assert_se(sd_netlink_open(&rtnl2) >= 0); @@ -164,6 +183,8 @@ static void test_event_loop(int ifindex) { _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; char *ifname; + log_debug("/* %s */", __func__); + ifname = strdup("lo2"); assert_se(ifname); @@ -194,6 +215,8 @@ static void test_async(int ifindex) { const char *description; char *ifname; + log_debug("/* %s */", __func__); + ifname = strdup("lo"); assert_se(ifname); @@ -225,6 +248,8 @@ static void test_slot_set(int ifindex) { const char *description; char *ifname; + log_debug("/* %s */", __func__); + ifname = strdup("lo"); assert_se(ifname); @@ -303,6 +328,8 @@ static void test_async_destroy_callback(int ifindex) { _cleanup_(sd_netlink_slot_unrefp) sd_netlink_slot *slot = NULL; char *ifname; + log_debug("/* %s */", __func__); + assert_se(t = new(struct test_async_object, 1)); assert_se(ifname = strdup("lo")); *t = (struct test_async_object) { @@ -371,6 +398,8 @@ static void test_pipe(int ifindex) { _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m1 = NULL, *m2 = NULL; int counter = 0; + log_debug("/* %s */", __func__); + assert_se(sd_netlink_open(&rtnl) >= 0); assert_se(sd_rtnl_message_new_link(rtnl, &m1, RTM_GETLINK, ifindex) >= 0); @@ -396,6 +425,8 @@ static void test_container(sd_netlink *rtnl) { uint32_t u32_data; const char *string_data; + log_debug("/* %s */", __func__); + assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_NEWLINK, 0) >= 0); assert_se(sd_netlink_message_open_container(m, IFLA_LINKINFO) >= 0); @@ -406,7 +437,7 @@ static void test_container(sd_netlink *rtnl) { assert_se(sd_netlink_message_close_container(m) >= 0); assert_se(sd_netlink_message_close_container(m) == -EINVAL); - assert_se(sd_netlink_message_rewind(m, NULL) >= 0); + assert_se(sd_netlink_message_rewind(m, rtnl) >= 0); assert_se(sd_netlink_message_enter_container(m, IFLA_LINKINFO) >= 0); assert_se(sd_netlink_message_read_string(m, IFLA_INFO_KIND, &string_data) >= 0); @@ -429,6 +460,8 @@ static void test_match(void) { _cleanup_(sd_netlink_slot_unrefp) sd_netlink_slot *s1 = NULL, *s2 = NULL; _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; + log_debug("/* %s */", __func__); + assert_se(sd_netlink_open(&rtnl) >= 0); assert_se(sd_netlink_add_match(rtnl, &s1, RTM_NEWLINK, link_handler, NULL, NULL, NULL) >= 0); @@ -445,6 +478,8 @@ static void test_get_addresses(sd_netlink *rtnl) { _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL; sd_netlink_message *m; + log_debug("/* %s */", __func__); + assert_se(sd_rtnl_message_new_addr(rtnl, &req, RTM_GETADDR, 0, AF_UNSPEC) >= 0); assert_se(sd_netlink_message_request_dump(req, true) >= 0); assert_se(sd_netlink_call(rtnl, req, 0, &reply) >= 0); @@ -472,7 +507,9 @@ static void test_get_addresses(sd_netlink *rtnl) { static void test_message(sd_netlink *rtnl) { _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; - assert_se(rtnl_message_new_synthetic_error(rtnl, -ETIMEDOUT, 1, &m) >= 0); + log_debug("/* %s */", __func__); + + assert_se(message_new_synthetic_error(rtnl, -ETIMEDOUT, 1, &m) >= 0); assert_se(sd_netlink_message_get_errno(m) == -ETIMEDOUT); } @@ -480,8 +517,10 @@ static void test_array(void) { _cleanup_(sd_netlink_unrefp) sd_netlink *genl = NULL; _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; + 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++) { @@ -496,7 +535,7 @@ static void test_array(void) { } assert_se(sd_netlink_message_close_container(m) >= 0); - rtnl_message_seal(m); + message_seal(m); assert_se(sd_netlink_message_rewind(m, genl) >= 0); assert_se(sd_netlink_message_enter_container(m, CTRL_ATTR_MCAST_GROUPS) >= 0); @@ -522,6 +561,8 @@ static void test_strv(sd_netlink *rtnl) { _cleanup_strv_free_ char **names_in = NULL, **names_out; const char *p; + log_debug("/* %s */", __func__); + assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_NEWLINKPROP, 1) >= 0); for (unsigned i = 0; i < 10; i++) { @@ -535,8 +576,8 @@ static void test_strv(sd_netlink *rtnl) { assert_se(sd_netlink_message_append_strv(m, IFLA_ALT_IFNAME, names_in) >= 0); assert_se(sd_netlink_message_close_container(m) >= 0); - rtnl_message_seal(m); - assert_se(sd_netlink_message_rewind(m, NULL) >= 0); + message_seal(m); + assert_se(sd_netlink_message_rewind(m, rtnl) >= 0); assert_se(sd_netlink_message_read_strv(m, IFLA_PROP_LIST, IFLA_ALT_IFNAME, &names_out) >= 0); assert_se(strv_equal(names_in, names_out)); @@ -547,6 +588,84 @@ static void test_strv(sd_netlink *rtnl) { assert_se(sd_netlink_message_exit_container(m) >= 0); } +static int genl_ctrl_match_callback(sd_netlink *genl, sd_netlink_message *m, void *userdata) { + const char *name; + uint16_t id; + uint8_t cmd; + + assert(genl); + assert(m); + + assert_se(sd_genl_message_get_family_name(genl, m, &name) >= 0); + assert_se(streq(name, CTRL_GENL_NAME)); + + assert_se(sd_genl_message_get_command(genl, m, &cmd) >= 0); + + switch (cmd) { + case CTRL_CMD_NEWFAMILY: + case CTRL_CMD_DELFAMILY: + assert_se(sd_netlink_message_read_string(m, CTRL_ATTR_FAMILY_NAME, &name) >= 0); + assert_se(sd_netlink_message_read_u16(m, CTRL_ATTR_FAMILY_ID, &id) >= 0); + log_debug("%s: %s (id=%"PRIu16") family is %s.", + __func__, name, id, cmd == CTRL_CMD_NEWFAMILY ? "added" : "removed"); + break; + case CTRL_CMD_NEWMCAST_GRP: + case CTRL_CMD_DELMCAST_GRP: + assert_se(sd_netlink_message_read_string(m, CTRL_ATTR_FAMILY_NAME, &name) >= 0); + assert_se(sd_netlink_message_read_u16(m, CTRL_ATTR_FAMILY_ID, &id) >= 0); + log_debug("%s: multicast group for %s (id=%"PRIu16") family is %s.", + __func__, name, id, cmd == CTRL_CMD_NEWMCAST_GRP ? "added" : "removed"); + break; + default: + log_debug("%s: received nlctrl message with unknown command '%"PRIu8"'.", __func__, cmd); + } + + return 0; +} + +static void test_genl(void) { + _cleanup_(sd_event_unrefp) sd_event *event = NULL; + _cleanup_(sd_netlink_unrefp) sd_netlink *genl = NULL; + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; + const char *name; + uint8_t cmd; + int r; + + log_debug("/* %s */", __func__); + + assert_se(sd_genl_socket_open(&genl) >= 0); + assert_se(sd_event_default(&event) >= 0); + assert_se(sd_netlink_attach_event(genl, event, 0) >= 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)); + assert_se(sd_genl_message_get_command(genl, m, &cmd) >= 0); + assert_se(cmd == CTRL_CMD_GETFAMILY); + + assert_se(sd_genl_add_match(genl, NULL, CTRL_GENL_NAME, "notify", 0, genl_ctrl_match_callback, NULL, NULL, "genl-ctrl-notify") >= 0); + + 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); + + /* These families may not be supported by kernel. Hence, ignore results. */ + (void) sd_genl_message_new(genl, FOU_GENL_NAME, 0, &m); + m = sd_netlink_message_unref(m); + (void) sd_genl_message_new(genl, L2TP_GENL_NAME, 0, &m); + m = sd_netlink_message_unref(m); + (void) sd_genl_message_new(genl, MACSEC_GENL_NAME, 0, &m); + m = sd_netlink_message_unref(m); + (void) sd_genl_message_new(genl, NL80211_GENL_NAME, 0, &m); + + for (;;) { + r = sd_event_run(event, 500 * USEC_PER_MSEC); + assert_se(r >= 0); + if (r == 0) + return; + } +} + int main(void) { sd_netlink *rtnl; sd_netlink_message *m; @@ -555,6 +674,8 @@ int main(void) { int if_loopback; uint16_t type; + test_setup_logging(LOG_DEBUG); + test_match(); test_multiple(); @@ -605,5 +726,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 f55e524ae9..b7b536f3b5 100644 --- a/src/network/test-network-tables.c +++ b/src/network/test-network-tables.c @@ -8,7 +8,6 @@ #include "lldp-internal.h" #include "macvlan.h" #include "ndisc-internal.h" -#include "netlink-internal.h" #include "networkd-link.h" #include "networkd-network.h" #include "networkd-util.h" @@ -35,7 +34,6 @@ int main(int argc, char **argv) { /* test_table(link_state, LINK_STATE); — not a reversible mapping */ test_table(lldp_mode, LLDP_MODE); test_table(netdev_kind, NETDEV_KIND); - test_table(nl_union_link_info_data, NL_UNION_LINK_INFO_DATA); test_table(radv_prefix_delegation, RADV_PREFIX_DELEGATION); test_table(lldp_event, SD_LLDP_EVENT); test_table(ndisc_event, SD_NDISC_EVENT); @@ -48,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/firewall-util-nft.c b/src/shared/firewall-util-nft.c index e68978d777..d6beaf20d8 100644 --- a/src/shared/firewall-util-nft.c +++ b/src/shared/firewall-util-nft.c @@ -649,7 +649,7 @@ static int fw_nftables_init_family(sd_netlink *nfnl, int family) { msgcnt++; assert(msgcnt < NFT_INIT_MSGS); /* Set F_EXCL so table add fails if the table already exists. */ - r = sd_nfnl_nft_message_new_table(nfnl, &batch[msgcnt], family, NFT_SYSTEMD_TABLE_NAME, NLM_F_EXCL | NLM_F_ACK); + r = sd_nfnl_nft_message_new_table(nfnl, &batch[msgcnt], family, NFT_SYSTEMD_TABLE_NAME); if (r < 0) goto out_unref; 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 b7e1a90958..5965780fbb 100644 --- a/src/systemd/sd-netlink.h +++ b/src/systemd/sd-netlink.h @@ -31,32 +31,15 @@ _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 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; /* bus */ -int sd_netlink_new_from_netlink(sd_netlink **nl, int fd); +int sd_netlink_new_from_fd(sd_netlink **nl, int fd); int sd_netlink_open(sd_netlink **nl); int sd_netlink_open_fd(sd_netlink **nl, int fd); int sd_netlink_inc_rcvbuf(sd_netlink *nl, const size_t size); @@ -86,6 +69,7 @@ int sd_netlink_add_match(sd_netlink *nl, sd_netlink_slot **ret_slot, uint16_t ma int sd_netlink_attach_event(sd_netlink *nl, sd_event *e, int64_t priority); int sd_netlink_detach_event(sd_netlink *nl); +/* message */ int sd_netlink_message_append_string(sd_netlink_message *m, unsigned short type, const char *data); int sd_netlink_message_append_strv(sd_netlink_message *m, unsigned short type, char * const *data); int sd_netlink_message_append_flag(sd_netlink_message *m, unsigned short type); @@ -129,7 +113,7 @@ 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 *genl); +int sd_netlink_message_rewind(sd_netlink_message *m, sd_netlink *nl); sd_netlink_message *sd_netlink_message_next(sd_netlink_message *m); @@ -182,12 +166,12 @@ int sd_rtnl_message_route_get_dst_prefixlen(sd_netlink_message *m, unsigned char int sd_rtnl_message_route_get_src_prefixlen(sd_netlink_message *m, unsigned char *src_len); int sd_rtnl_message_route_get_type(sd_netlink_message *m, unsigned char *type); -int sd_rtnl_message_new_nexthop(sd_netlink *rtnl, sd_netlink_message **ret, uint16_t nhmsg_type, int nh_family, unsigned char nh_protocol); +int sd_rtnl_message_new_nexthop(sd_netlink *rtnl, sd_netlink_message **ret, uint16_t nlmsg_type, int nh_family, unsigned char nh_protocol); int sd_rtnl_message_nexthop_set_flags(sd_netlink_message *m, uint8_t flags); int sd_rtnl_message_nexthop_get_family(sd_netlink_message *m, uint8_t *family); int sd_rtnl_message_nexthop_get_protocol(sd_netlink_message *m, uint8_t *protocol); -int sd_rtnl_message_new_neigh(sd_netlink *nl, sd_netlink_message **ret, uint16_t msg_type, int index, int nda_family); +int sd_rtnl_message_new_neigh(sd_netlink *nl, sd_netlink_message **ret, uint16_t nlmsg_type, int index, int nda_family); int sd_rtnl_message_neigh_set_flags(sd_netlink_message *m, uint8_t flags); int sd_rtnl_message_neigh_set_state(sd_netlink_message *m, uint16_t state); int sd_rtnl_message_neigh_get_family(sd_netlink_message *m, int *family); @@ -224,13 +208,13 @@ int sd_rtnl_message_set_tclass_handle(sd_netlink_message *m, uint32_t handle); int sd_rtnl_message_new_mdb(sd_netlink *rtnl, sd_netlink_message **ret, uint16_t nlmsg_type, int mdb_ifindex); /* nfnl */ -int sd_nfnl_socket_open(sd_netlink **nl); +int sd_nfnl_socket_open(sd_netlink **ret); int sd_nfnl_message_batch_begin(sd_netlink *nfnl, sd_netlink_message **ret); int sd_nfnl_message_batch_end(sd_netlink *nfnl, sd_netlink_message **ret); int sd_nfnl_nft_message_del_table(sd_netlink *nfnl, sd_netlink_message **ret, int family, const char *table); int sd_nfnl_nft_message_new_table(sd_netlink *nfnl, sd_netlink_message **ret, - int family, const char *table, uint16_t nl_flags); + int family, const char *table); int sd_nfnl_nft_message_new_basechain(sd_netlink *nfnl, sd_netlink_message **ret, int family, const char *table, const char *chain, const char *type, uint8_t hook, int prio); @@ -250,13 +234,19 @@ int sd_nfnl_nft_message_add_setelem(sd_netlink_message *m, int sd_nfnl_nft_message_add_setelem_end(sd_netlink_message *m); /* genl */ -int sd_genl_socket_open(sd_netlink **nl); -int sd_genl_message_new(sd_netlink *nl, sd_genl_family_t family, uint8_t cmd, sd_netlink_message **ret); -int sd_genl_message_get_family(sd_netlink *nl, sd_netlink_message *m, sd_genl_family_t *ret); +int sd_genl_socket_open(sd_netlink **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); +int sd_genl_message_get_command(sd_netlink *genl, sd_netlink_message *m, uint8_t *ret); +int sd_genl_add_match(sd_netlink *nl, sd_netlink_slot **ret_slot, const char *family_name, + const char *multicast_group_name, uint8_t command, + sd_netlink_message_handler_t callback, + sd_netlink_destroy_t destroy_callback, + void *userdata, const char *description); /* slot */ -sd_netlink_slot *sd_netlink_slot_ref(sd_netlink_slot *nl); -sd_netlink_slot *sd_netlink_slot_unref(sd_netlink_slot *nl); +sd_netlink_slot *sd_netlink_slot_ref(sd_netlink_slot *slot); +sd_netlink_slot *sd_netlink_slot_unref(sd_netlink_slot *slot); sd_netlink *sd_netlink_slot_get_netlink(sd_netlink_slot *slot); void *sd_netlink_slot_get_userdata(sd_netlink_slot *slot); |