summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYu Watanabe <watanabe.yu+github@gmail.com>2021-08-29 22:37:31 +0900
committerGitHub <noreply@github.com>2021-08-29 22:37:31 +0900
commit4917c15af7c2dfe553b8e0dbf22b4fb7cec958de (patch)
tree6db870e157004b0a62f1d1416a389ae99045acf5
parent9c53de8bc591173e27b9eccd52d0adb66d0c250b (diff)
parent98be429243ba1d0505c98c7f64f89076ed5deb85 (diff)
downloadsystemd-4917c15af7c2dfe553b8e0dbf22b4fb7cec958de.tar.gz
Merge pull request #20057 from yuwata/sd-netlink-genl-cleanups
sd-netlink: cleanups for generic netlink
-rw-r--r--src/basic/linux/genetlink.h102
-rw-r--r--src/basic/meson.build1
-rw-r--r--src/libsystemd/meson.build12
-rw-r--r--src/libsystemd/sd-netlink/generic-netlink.c179
-rw-r--r--src/libsystemd/sd-netlink/generic-netlink.h6
-rw-r--r--src/libsystemd/sd-netlink/netlink-genl.c473
-rw-r--r--src/libsystemd/sd-netlink/netlink-genl.h8
-rw-r--r--src/libsystemd/sd-netlink/netlink-internal.h52
-rw-r--r--src/libsystemd/sd-netlink/netlink-message-nfnl.c (renamed from src/libsystemd/sd-netlink/nfnl-message.c)149
-rw-r--r--src/libsystemd/sd-netlink/netlink-message-rtnl.c (renamed from src/libsystemd/sd-netlink/rtnl-message.c)10
-rw-r--r--src/libsystemd/sd-netlink/netlink-message.c285
-rw-r--r--src/libsystemd/sd-netlink/netlink-slot.c24
-rw-r--r--src/libsystemd/sd-netlink/netlink-socket.c64
-rw-r--r--src/libsystemd/sd-netlink/netlink-types-genl.c234
-rw-r--r--src/libsystemd/sd-netlink/netlink-types-internal.h49
-rw-r--r--src/libsystemd/sd-netlink/netlink-types-nfnl.c197
-rw-r--r--src/libsystemd/sd-netlink/netlink-types-rtnl.c872
-rw-r--r--src/libsystemd/sd-netlink/netlink-types.c1838
-rw-r--r--src/libsystemd/sd-netlink/netlink-types.h121
-rw-r--r--src/libsystemd/sd-netlink/netlink-util.c19
-rw-r--r--src/libsystemd/sd-netlink/netlink-util.h4
-rw-r--r--src/libsystemd/sd-netlink/sd-netlink.c530
-rw-r--r--src/libsystemd/sd-netlink/test-netlink.c141
-rw-r--r--src/network/netdev/batadv.c2
-rw-r--r--src/network/netdev/fou-tunnel.c2
-rw-r--r--src/network/netdev/l2tp-tunnel.c4
-rw-r--r--src/network/netdev/macsec.c2
-rw-r--r--src/network/netdev/wireguard.c2
-rw-r--r--src/network/test-network-tables.c3
-rw-r--r--src/shared/firewall-util-nft.c2
-rw-r--r--src/shared/wifi-util.c21
-rw-r--r--src/systemd/sd-netlink.h46
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);