1
1
mirror of https://github.com/systemd/systemd-stable.git synced 2025-01-06 13:17:44 +03:00

Merge pull request from yuwata/sd-netlink-genl-cleanups

sd-netlink: cleanups for generic netlink
This commit is contained in:
Yu Watanabe 2021-08-29 22:37:31 +09:00 committed by GitHub
commit 4917c15af7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
32 changed files with 2808 additions and 2660 deletions

102
src/basic/linux/genetlink.h Normal file
View File

@ -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 */

View File

@ -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

View File

@ -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

View File

@ -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);
}

View File

@ -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);

View File

@ -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);
}

View File

@ -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);

View File

@ -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);
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 rtnl connection */
#define NETLINK_DONT_DESTROY(rtnl) \
_cleanup_(sd_netlink_unrefp) _unused_ sd_netlink *_dont_destroy_##rtnl = sd_netlink_ref(rtnl)
/* 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)

View File

@ -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;

View File

@ -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);

View File

@ -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);
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;
r = message_new_empty(rtnl, &m);
if (r < 0)
return r;
size = NLMSG_SPACE(type_get_size(nl_type));
assert(nl);
assert(type_system);
assert(ret);
size = NLMSG_SPACE(header_size);
assert(size >= sizeof(struct nlmsghdr));
r = message_new_empty(nl, &m);
if (r < 0)
return r;
m->containers[0].type_system = type_system;
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 (sd_netlink_message_is_error(m))
return netlink_message_parse_error(m);
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;
}
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;
}

View File

@ -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);
for (size_t i = 0; i < slot->match_callback.n_groups; i++)
(void) socket_broadcast_group_unref(nl, slot->match_callback.groups[i]);
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;
}
slot->match_callback.n_groups = 0;
slot->match_callback.groups = mfree(slot->match_callback.groups);
break;
default:

View File

@ -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;

View File

@ -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);
}

View File

@ -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)

View File

@ -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));
}

View File

@ -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);
}

File diff suppressed because it is too large Load Diff

View File

@ -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_get_type_system(const NLType *type);
const NLTypeSystemUnion *type_get_type_system_union(const NLType *type);
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);
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);
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_;
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;
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);

View File

@ -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");
}

View File

@ -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);
}

File diff suppressed because it is too large Load Diff

View File

@ -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;
}

View File

@ -122,7 +122,7 @@ static int netdev_batadv_post_create(NetDev *netdev, Link *link, sd_netlink_mess
b = BATADV(netdev);
assert(b);
r = sd_genl_message_new(netdev->manager->genl, SD_GENL_BATADV, BATADV_CMD_SET_MESH, &message);
r = sd_genl_message_new(netdev->manager->genl, BATADV_NL_NAME, BATADV_CMD_SET_MESH, &message);
if (r < 0)
return log_netdev_error_errno(netdev, r, "Failed to allocate generic netlink message: %m");

View File

@ -36,7 +36,7 @@ static int netdev_fill_fou_tunnel_message(NetDev *netdev, sd_netlink_message **r
assert(t);
r = sd_genl_message_new(netdev->manager->genl, SD_GENL_FOU, FOU_CMD_ADD, &m);
r = sd_genl_message_new(netdev->manager->genl, FOU_GENL_NAME, FOU_CMD_ADD, &m);
if (r < 0)
return log_netdev_error_errno(netdev, r, "Failed to allocate generic netlink message: %m");

View File

@ -104,7 +104,7 @@ static int netdev_l2tp_fill_message_tunnel(NetDev *netdev, union in_addr_union *
assert(t);
r = sd_genl_message_new(netdev->manager->genl, SD_GENL_L2TP, L2TP_CMD_TUNNEL_CREATE, &m);
r = sd_genl_message_new(netdev->manager->genl, L2TP_GENL_NAME, L2TP_CMD_TUNNEL_CREATE, &m);
if (r < 0)
return log_netdev_error_errno(netdev, r, "Failed to create generic netlink message: %m");
@ -195,7 +195,7 @@ static int netdev_l2tp_fill_message_session(NetDev *netdev, L2tpSession *session
assert(session);
assert(session->tunnel);
r = sd_genl_message_new(netdev->manager->genl, SD_GENL_L2TP, L2TP_CMD_SESSION_CREATE, &m);
r = sd_genl_message_new(netdev->manager->genl, L2TP_GENL_NAME, L2TP_CMD_SESSION_CREATE, &m);
if (r < 0)
return log_netdev_error_errno(netdev, r, "Failed to create generic netlink message: %m");

View File

@ -224,7 +224,7 @@ static int netdev_macsec_fill_message(NetDev *netdev, int command, sd_netlink_me
assert(netdev);
assert(netdev->ifindex > 0);
r = sd_genl_message_new(netdev->manager->genl, SD_GENL_MACSEC, command, &m);
r = sd_genl_message_new(netdev->manager->genl, MACSEC_GENL_NAME, command, &m);
if (r < 0)
return log_netdev_error_errno(netdev, r, "Failed to create generic netlink message: %m");

View File

@ -229,7 +229,7 @@ static int wireguard_set_interface(NetDev *netdev) {
message = sd_netlink_message_unref(message);
r = sd_genl_message_new(netdev->manager->genl, SD_GENL_WIREGUARD, WG_CMD_SET_DEVICE, &message);
r = sd_genl_message_new(netdev->manager->genl, WG_GENL_NAME, WG_CMD_SET_DEVICE, &message);
if (r < 0)
return log_netdev_error_errno(netdev, r, "Failed to allocate generic netlink message: %m");

View File

@ -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;
}

View File

@ -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;

View File

@ -1,17 +1,18 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "log.h"
#include "string-util.h"
#include "wifi-util.h"
int wifi_get_interface(sd_netlink *genl, int ifindex, enum nl80211_iftype *iftype, char **ssid) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL, *reply = NULL;
sd_genl_family_t family;
const char *family;
int r;
assert(genl);
assert(ifindex > 0);
r = sd_genl_message_new(genl, SD_GENL_NL80211, NL80211_CMD_GET_INTERFACE, &m);
r = sd_genl_message_new(genl, NL80211_GENL_NAME, NL80211_CMD_GET_INTERFACE, &m);
if (r < 0)
return log_debug_errno(r, "Failed to create generic netlink message: %m");
@ -38,11 +39,11 @@ int wifi_get_interface(sd_netlink *genl, int ifindex, enum nl80211_iftype *iftyp
if (r < 0)
return log_debug_errno(r, "Failed to get information about wifi interface %d: %m", ifindex);
r = sd_genl_message_get_family(genl, reply, &family);
r = sd_genl_message_get_family_name(genl, reply, &family);
if (r < 0)
return log_debug_errno(r, "Failed to determine genl family: %m");
if (family != SD_GENL_NL80211) {
log_debug("Received message of unexpected genl family %" PRIi64 ", ignoring.", family);
if (!streq(family, NL80211_GENL_NAME)) {
log_debug("Received message of unexpected genl family '%s', ignoring.", family);
goto nodata;
}
@ -75,14 +76,14 @@ nodata:
int wifi_get_station(sd_netlink *genl, int ifindex, struct ether_addr *bssid) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL, *reply = NULL;
sd_genl_family_t family;
const char *family;
int r;
assert(genl);
assert(ifindex > 0);
assert(bssid);
r = sd_genl_message_new(genl, SD_GENL_NL80211, NL80211_CMD_GET_STATION, &m);
r = sd_genl_message_new(genl, NL80211_GENL_NAME, NL80211_CMD_GET_STATION, &m);
if (r < 0)
return log_debug_errno(r, "Failed to create generic netlink message: %m");
@ -106,11 +107,11 @@ int wifi_get_station(sd_netlink *genl, int ifindex, struct ether_addr *bssid) {
if (r < 0)
return log_debug_errno(r, "Failed to get information about wifi station: %m");
r = sd_genl_message_get_family(genl, reply, &family);
r = sd_genl_message_get_family_name(genl, reply, &family);
if (r < 0)
return log_debug_errno(r, "Failed to determine genl family: %m");
if (family != SD_GENL_NL80211) {
log_debug("Received message of unexpected genl family %" PRIi64 ", ignoring.", family);
if (!streq(family, NL80211_GENL_NAME)) {
log_debug("Received message of unexpected genl family '%s', ignoring.", family);
goto nodata;
}

View File

@ -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);