mirror of
https://github.com/systemd/systemd-stable.git
synced 2025-02-09 09:57:26 +03:00
sd-netlink: add generic netlink support
This also adds the ability to incorporate arrays into netlink messages and to determine when a netlink message is too big, used by some generic netlink protocols.
This commit is contained in:
parent
8481e3e71e
commit
05d0c2e3cf
@ -74,6 +74,7 @@ libsystemd_internal_sources = files('''
|
||||
sd-id128/id128-util.c
|
||||
sd-id128/id128-util.h
|
||||
sd-id128/sd-id128.c
|
||||
sd-netlink/generic-netlink.c
|
||||
sd-netlink/local-addresses.c
|
||||
sd-netlink/local-addresses.h
|
||||
sd-netlink/netlink-internal.h
|
||||
|
96
src/libsystemd/sd-netlink/generic-netlink.c
Normal file
96
src/libsystemd/sd-netlink/generic-netlink.c
Normal file
@ -0,0 +1,96 @@
|
||||
#include <linux/genetlink.h>
|
||||
|
||||
#include "sd-netlink.h"
|
||||
#include "netlink-internal.h"
|
||||
#include "alloc-util.h"
|
||||
|
||||
typedef struct {
|
||||
const char* name;
|
||||
uint8_t version;
|
||||
} genl_family;
|
||||
|
||||
static const genl_family genl_families[] = {
|
||||
[SD_GENL_ID_CTRL] = { .name = "", .version = 1 },
|
||||
};
|
||||
|
||||
int sd_genl_socket_open(sd_netlink **ret) {
|
||||
return netlink_open_family(ret, NETLINK_GENERIC);
|
||||
}
|
||||
static int lookup_id(sd_netlink *nl, sd_genl_family family, uint16_t *id);
|
||||
|
||||
static int genl_message_new(sd_netlink *nl, sd_genl_family family, uint16_t nlmsg_type, uint8_t cmd, sd_netlink_message **ret) {
|
||||
int r;
|
||||
struct genlmsghdr *genl;
|
||||
const NLType *genl_cmd_type, *nl_type;
|
||||
const NLTypeSystem *type_system;
|
||||
size_t size;
|
||||
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
|
||||
|
||||
assert_return(nl->protocol == NETLINK_GENERIC, -EINVAL);
|
||||
|
||||
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);
|
||||
genl = NLMSG_DATA(m->hdr);
|
||||
genl->cmd = cmd;
|
||||
genl->version = genl_families[family].version;
|
||||
|
||||
*ret = m;
|
||||
m = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_genl_message_new(sd_netlink *nl, sd_genl_family family, uint8_t cmd, sd_netlink_message **ret) {
|
||||
int r;
|
||||
uint16_t id = GENL_ID_CTRL;
|
||||
|
||||
if (family != SD_GENL_ID_CTRL) {
|
||||
r = lookup_id(nl, family, &id);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
return genl_message_new(nl, family, id, cmd, ret);
|
||||
}
|
||||
|
||||
static int lookup_id(sd_netlink *nl, sd_genl_family family, uint16_t *id) {
|
||||
int r;
|
||||
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
|
||||
|
||||
r = sd_genl_message_new(nl, SD_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;
|
||||
|
||||
return sd_netlink_message_read_u16(reply, CTRL_ATTR_FAMILY_ID, id);
|
||||
}
|
@ -62,6 +62,8 @@ struct sd_netlink {
|
||||
struct sockaddr_nl nl;
|
||||
} sockaddr;
|
||||
|
||||
int protocol;
|
||||
|
||||
Hashmap *broadcast_group_refs;
|
||||
bool broadcast_group_dont_leave:1; /* until we can rely on 4.2 */
|
||||
|
||||
@ -111,6 +113,8 @@ struct sd_netlink_message {
|
||||
|
||||
sd_netlink *rtnl;
|
||||
|
||||
int protocol;
|
||||
|
||||
struct nlmsghdr *hdr;
|
||||
struct netlink_container containers[RTNL_CONTAINER_DEPTH];
|
||||
unsigned n_containers; /* number of containers */
|
||||
@ -123,6 +127,8 @@ struct sd_netlink_message {
|
||||
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 netlink_open_family(sd_netlink **ret, int family);
|
||||
|
||||
int socket_open(int family);
|
||||
int socket_bind(sd_netlink *nl);
|
||||
int socket_broadcast_group_ref(sd_netlink *nl, unsigned group);
|
||||
|
@ -55,7 +55,7 @@ int message_new_empty(sd_netlink *rtnl, sd_netlink_message **ret) {
|
||||
return -ENOMEM;
|
||||
|
||||
m->n_ref = REFCNT_INIT;
|
||||
|
||||
m->protocol = rtnl->protocol;
|
||||
m->sealed = false;
|
||||
|
||||
*ret = m;
|
||||
@ -66,10 +66,15 @@ int message_new_empty(sd_netlink *rtnl, sd_netlink_message **ret) {
|
||||
int message_new(sd_netlink *rtnl, sd_netlink_message **ret, uint16_t type) {
|
||||
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
|
||||
const NLType *nl_type;
|
||||
const NLTypeSystem *type_system_root;
|
||||
size_t size;
|
||||
int r;
|
||||
|
||||
r = type_system_get_type(&type_system_root, &nl_type, type);
|
||||
assert_return(rtnl, -EINVAL);
|
||||
|
||||
type_system_root = type_system_get_root(rtnl->protocol);
|
||||
|
||||
r = type_system_get_type(type_system_root, &nl_type, type);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@ -186,6 +191,10 @@ static int add_rtattr(sd_netlink_message *m, unsigned short type, const void *da
|
||||
/* get the new message size (with padding at the end) */
|
||||
message_length = offset + RTA_ALIGN(rta_length);
|
||||
|
||||
/* buffer should be smaller than both one page or 8K to be accepted by the kernel */
|
||||
if (message_length > MIN(page_size(), 8192UL))
|
||||
return -ENOBUFS;
|
||||
|
||||
/* realloc to fit the new attribute */
|
||||
new_hdr = realloc(m->hdr, message_length);
|
||||
if (!new_hdr)
|
||||
@ -490,7 +499,7 @@ int sd_netlink_message_open_container_union(sd_netlink_message *m, unsigned shor
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* do we evere need non-null size */
|
||||
/* do we ever need non-null size */
|
||||
r = add_rtattr(m, type | NLA_F_NESTED, NULL, 0);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@ -500,18 +509,57 @@ int sd_netlink_message_open_container_union(sd_netlink_message *m, unsigned shor
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int sd_netlink_message_close_container(sd_netlink_message *m) {
|
||||
assert_return(m, -EINVAL);
|
||||
assert_return(!m->sealed, -EPERM);
|
||||
assert_return(m->n_containers > 0, -EINVAL);
|
||||
|
||||
m->containers[m->n_containers].type_system = NULL;
|
||||
m->containers[m->n_containers].offset = 0;
|
||||
m->n_containers--;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_netlink_message_open_array(sd_netlink_message *m, uint16_t type) {
|
||||
int r;
|
||||
|
||||
assert_return(m, -EINVAL);
|
||||
assert_return(!m->sealed, -EPERM);
|
||||
assert_return(m->n_containers > 0, -EINVAL);
|
||||
|
||||
r = add_rtattr(m, type | NLA_F_NESTED, NULL, 0);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
m->containers[m->n_containers].offset = r;
|
||||
m->n_containers++;
|
||||
m->containers[m->n_containers].type_system = m->containers[m->n_containers - 1].type_system;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_netlink_message_cancel_array(sd_netlink_message *m) {
|
||||
unsigned i;
|
||||
uint32_t rta_len;
|
||||
|
||||
assert_return(m, -EINVAL);
|
||||
assert_return(!m->sealed, -EPERM);
|
||||
assert_return(m->n_containers > 1, -EINVAL);
|
||||
|
||||
rta_len = GET_CONTAINER(m, (m->n_containers - 1))->rta_len;
|
||||
|
||||
for (i = 0; i < m->n_containers; i++)
|
||||
GET_CONTAINER(m, i)->rta_len -= rta_len;
|
||||
|
||||
m->hdr->nlmsg_len -= rta_len;
|
||||
|
||||
m->n_containers--;
|
||||
m->containers[m->n_containers].type_system = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int netlink_message_read_internal(sd_netlink_message *m, unsigned short type, void **data, bool *net_byteorder) {
|
||||
struct netlink_attribute *attribute;
|
||||
struct rtattr *rta;
|
||||
@ -899,6 +947,7 @@ int sd_netlink_message_get_errno(sd_netlink_message *m) {
|
||||
|
||||
int sd_netlink_message_rewind(sd_netlink_message *m) {
|
||||
const NLType *nl_type;
|
||||
const NLTypeSystem *type_system_root;
|
||||
uint16_t type;
|
||||
size_t size;
|
||||
unsigned i;
|
||||
@ -910,6 +959,8 @@ int sd_netlink_message_rewind(sd_netlink_message *m) {
|
||||
if (!m->sealed)
|
||||
rtnl_message_seal(m);
|
||||
|
||||
type_system_root = type_system_get_root(m->protocol);
|
||||
|
||||
for (i = 1; i <= m->n_containers; i++)
|
||||
m->containers[i].attributes = mfree(m->containers[i].attributes);
|
||||
|
||||
@ -921,7 +972,7 @@ int sd_netlink_message_rewind(sd_netlink_message *m) {
|
||||
|
||||
assert(m->hdr);
|
||||
|
||||
r = type_system_get_type(&type_system_root, &nl_type, m->hdr->nlmsg_type);
|
||||
r = type_system_get_type(type_system_root, &nl_type, m->hdr->nlmsg_type);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
@ -330,11 +330,14 @@ int socket_read_message(sd_netlink *rtnl) {
|
||||
size_t len;
|
||||
int r;
|
||||
unsigned i = 0;
|
||||
const NLTypeSystem *type_system_root;
|
||||
|
||||
assert(rtnl);
|
||||
assert(rtnl->rbuffer);
|
||||
assert(rtnl->rbuffer_allocated >= sizeof(struct nlmsghdr));
|
||||
|
||||
type_system_root = type_system_get_root(rtnl->protocol);
|
||||
|
||||
/* read nothing, just get the pending message size */
|
||||
r = socket_recv_message(rtnl->fd, &iov, NULL, true);
|
||||
if (r <= 0)
|
||||
@ -396,7 +399,8 @@ int socket_read_message(sd_netlink *rtnl) {
|
||||
}
|
||||
|
||||
/* check that we support this message type */
|
||||
r = type_system_get_type(&type_system_root, &nl_type, new_msg->nlmsg_type);
|
||||
r = type_system_get_type(type_system_root, &nl_type, new_msg->nlmsg_type);
|
||||
|
||||
if (r < 0) {
|
||||
if (r == -EOPNOTSUPP)
|
||||
log_debug("sd-netlink: ignored message with unknown type: %i",
|
||||
|
@ -36,6 +36,7 @@
|
||||
#include <linux/if_link.h>
|
||||
#include <linux/if_tunnel.h>
|
||||
#include <linux/fib_rules.h>
|
||||
#include <linux/genetlink.h>
|
||||
|
||||
#if HAVE_VXCAN_INFO_PEER
|
||||
#include <linux/can/vxcan.h>
|
||||
@ -46,6 +47,7 @@
|
||||
#include "netlink-types.h"
|
||||
#include "string-table.h"
|
||||
#include "util.h"
|
||||
#include "sd-netlink.h"
|
||||
|
||||
/* Maximum ARP IP target defined in kernel */
|
||||
#define BOND_MAX_ARP_TARGETS 16
|
||||
@ -665,11 +667,49 @@ static const NLType rtnl_types[] = {
|
||||
[RTM_GETRULE] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_routing_policy_rule_type_system, .size = sizeof(struct rtmsg) },
|
||||
};
|
||||
|
||||
const NLTypeSystem type_system_root = {
|
||||
const NLTypeSystem rtnl_type_system_root = {
|
||||
.count = ELEMENTSOF(rtnl_types),
|
||||
.types = rtnl_types,
|
||||
};
|
||||
|
||||
|
||||
static const NLType genl_get_family_types[] = {
|
||||
[CTRL_ATTR_FAMILY_NAME] = { .type = NETLINK_TYPE_STRING },
|
||||
[CTRL_ATTR_FAMILY_ID] = { .type = NETLINK_TYPE_U16 },
|
||||
};
|
||||
|
||||
static const NLTypeSystem genl_get_family_type_system = {
|
||||
.count = ELEMENTSOF(genl_get_family_types),
|
||||
.types = genl_get_family_types,
|
||||
};
|
||||
|
||||
static const NLType genl_ctrl_id_ctrl_cmds[] = {
|
||||
[CTRL_CMD_GETFAMILY] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_get_family_type_system },
|
||||
};
|
||||
|
||||
static const NLTypeSystem genl_ctrl_id_ctrl_type_system = {
|
||||
.count = ELEMENTSOF(genl_ctrl_id_ctrl_cmds),
|
||||
.types = genl_ctrl_id_ctrl_cmds,
|
||||
};
|
||||
|
||||
static const NLType genl_families[] = {
|
||||
[SD_GENL_ID_CTRL] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_ctrl_id_ctrl_type_system },
|
||||
};
|
||||
|
||||
const NLTypeSystem genl_family_type_system_root = {
|
||||
.count = ELEMENTSOF(genl_families),
|
||||
.types = genl_families,
|
||||
};
|
||||
|
||||
static const NLType genl_types[] = {
|
||||
[GENL_ID_CTRL] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_get_family_type_system, .size = sizeof(struct genlmsghdr) },
|
||||
};
|
||||
|
||||
const NLTypeSystem genl_type_system_root = {
|
||||
.count = ELEMENTSOF(genl_types),
|
||||
.types = genl_types,
|
||||
};
|
||||
|
||||
uint16_t type_get_type(const NLType *type) {
|
||||
assert(type);
|
||||
return type->type;
|
||||
@ -703,6 +743,15 @@ uint16_t type_system_get_count(const NLTypeSystem *type_system) {
|
||||
return type_system->count;
|
||||
}
|
||||
|
||||
const NLTypeSystem *type_system_get_root(int protocol) {
|
||||
switch (protocol) {
|
||||
case NETLINK_GENERIC:
|
||||
return &genl_type_system_root;
|
||||
default: /* NETLINK_ROUTE: */
|
||||
return &rtnl_type_system_root;
|
||||
}
|
||||
}
|
||||
|
||||
int type_system_get_type(const NLTypeSystem *type_system, const NLType **ret, uint16_t type) {
|
||||
const NLType *nl_type;
|
||||
|
||||
|
@ -54,13 +54,16 @@ struct NLTypeSystemUnion {
|
||||
const NLTypeSystem *type_systems;
|
||||
};
|
||||
|
||||
extern const NLTypeSystem type_system_root;
|
||||
extern const NLTypeSystem rtnl_type_system_root;
|
||||
extern const NLTypeSystem genl_type_system_root;
|
||||
extern const NLTypeSystem genl_family_type_system_root;
|
||||
|
||||
uint16_t type_get_type(const NLType *type);
|
||||
size_t type_get_size(const NLType *type);
|
||||
void type_get_type_system(const NLType *type, const NLTypeSystem **ret);
|
||||
void type_get_type_system_union(const NLType *type, const NLTypeSystemUnion **ret);
|
||||
|
||||
const NLTypeSystem* type_system_get_root(int protocol);
|
||||
uint16_t type_system_get_count(const NLTypeSystem *type_system);
|
||||
int type_system_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);
|
||||
|
@ -98,13 +98,13 @@ int rtnl_set_link_properties(sd_netlink **rtnl, int ifindex, const char *alias,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rtnl_message_new_synthetic_error(int error, uint32_t serial, sd_netlink_message **ret) {
|
||||
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(NULL, ret, NLMSG_ERROR);
|
||||
r = message_new(rtnl, ret, NLMSG_ERROR);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
@ -24,7 +24,7 @@
|
||||
|
||||
#include "util.h"
|
||||
|
||||
int rtnl_message_new_synthetic_error(int error, uint32_t serial, sd_netlink_message **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);
|
||||
|
||||
|
@ -46,6 +46,7 @@ static int sd_netlink_new(sd_netlink **ret) {
|
||||
rtnl->fd = -1;
|
||||
rtnl->sockaddr.nl.nl_family = AF_NETLINK;
|
||||
rtnl->original_pid = getpid_cached();
|
||||
rtnl->protocol = -1;
|
||||
|
||||
LIST_HEAD_INIT(rtnl->match_callbacks);
|
||||
|
||||
@ -106,6 +107,8 @@ static bool rtnl_pid_changed(sd_netlink *rtnl) {
|
||||
int sd_netlink_open_fd(sd_netlink **ret, int fd) {
|
||||
_cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
|
||||
int r;
|
||||
int protocol;
|
||||
socklen_t l;
|
||||
|
||||
assert_return(ret, -EINVAL);
|
||||
assert_return(fd >= 0, -EBADF);
|
||||
@ -114,11 +117,18 @@ int sd_netlink_open_fd(sd_netlink **ret, int fd) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
l = sizeof(protocol);
|
||||
r = getsockopt(fd, SOL_SOCKET, SO_PROTOCOL, &protocol, &l);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
rtnl->fd = fd;
|
||||
rtnl->protocol = protocol;
|
||||
|
||||
r = socket_bind(rtnl);
|
||||
if (r < 0) {
|
||||
rtnl->fd = -1; /* on failure, the caller remains owner of the fd, hence don't close it here */
|
||||
rtnl->protocol = -1;
|
||||
return r;
|
||||
}
|
||||
|
||||
@ -128,11 +138,11 @@ int sd_netlink_open_fd(sd_netlink **ret, int fd) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_netlink_open(sd_netlink **ret) {
|
||||
int netlink_open_family(sd_netlink **ret, int family) {
|
||||
_cleanup_close_ int fd = -1;
|
||||
int r;
|
||||
|
||||
fd = socket_open(NETLINK_ROUTE);
|
||||
fd = socket_open(family);
|
||||
if (fd < 0)
|
||||
return fd;
|
||||
|
||||
@ -145,6 +155,10 @@ int sd_netlink_open(sd_netlink **ret) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_netlink_open(sd_netlink **ret) {
|
||||
return netlink_open_family(ret, NETLINK_ROUTE);
|
||||
}
|
||||
|
||||
int sd_netlink_inc_rcvbuf(sd_netlink *rtnl, size_t size) {
|
||||
assert_return(rtnl, -EINVAL);
|
||||
assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
|
||||
@ -309,7 +323,7 @@ static int process_timeout(sd_netlink *rtnl) {
|
||||
if (c->timeout > n)
|
||||
return 0;
|
||||
|
||||
r = rtnl_message_new_synthetic_error(-ETIMEDOUT, c->serial, &m);
|
||||
r = rtnl_message_new_synthetic_error(rtnl, -ETIMEDOUT, c->serial, &m);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
@ -143,13 +143,13 @@ static void test_address_get(sd_netlink *rtnl, int ifindex) {
|
||||
|
||||
}
|
||||
|
||||
static void test_route(void) {
|
||||
static void test_route(sd_netlink *rtnl) {
|
||||
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req;
|
||||
struct in_addr addr, addr_data;
|
||||
uint32_t index = 2, u32_data;
|
||||
int r;
|
||||
|
||||
r = sd_rtnl_message_new_route(NULL, &req, RTM_NEWROUTE, AF_INET, RTPROT_STATIC);
|
||||
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");
|
||||
return;
|
||||
@ -291,13 +291,13 @@ static void test_pipe(int ifindex) {
|
||||
assert_se((rtnl = sd_netlink_unref(rtnl)) == NULL);
|
||||
}
|
||||
|
||||
static void test_container(void) {
|
||||
static void test_container(sd_netlink *rtnl) {
|
||||
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
|
||||
uint16_t u16_data;
|
||||
uint32_t u32_data;
|
||||
const char *string_data;
|
||||
|
||||
assert_se(sd_rtnl_message_new_link(NULL, &m, RTM_NEWLINK, 0) >= 0);
|
||||
assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_NEWLINK, 0) >= 0);
|
||||
|
||||
assert_se(sd_netlink_message_open_container(m, IFLA_LINKINFO) >= 0);
|
||||
assert_se(sd_netlink_message_open_container_union(m, IFLA_INFO_DATA, "vlan") >= 0);
|
||||
@ -369,10 +369,10 @@ static void test_get_addresses(sd_netlink *rtnl) {
|
||||
}
|
||||
}
|
||||
|
||||
static void test_message(void) {
|
||||
static void test_message(sd_netlink *rtnl) {
|
||||
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
|
||||
|
||||
assert_se(rtnl_message_new_synthetic_error(-ETIMEDOUT, 1, &m) >= 0);
|
||||
assert_se(rtnl_message_new_synthetic_error(rtnl, -ETIMEDOUT, 1, &m) >= 0);
|
||||
assert_se(sd_netlink_message_get_errno(m) == -ETIMEDOUT);
|
||||
}
|
||||
|
||||
@ -384,19 +384,19 @@ int main(void) {
|
||||
int if_loopback;
|
||||
uint16_t type;
|
||||
|
||||
test_message();
|
||||
|
||||
test_match();
|
||||
|
||||
test_multiple();
|
||||
|
||||
test_route();
|
||||
|
||||
test_container();
|
||||
|
||||
assert_se(sd_netlink_open(&rtnl) >= 0);
|
||||
assert_se(rtnl);
|
||||
|
||||
test_route(rtnl);
|
||||
|
||||
test_message(rtnl);
|
||||
|
||||
test_container(rtnl);
|
||||
|
||||
if_loopback = (int) if_nametoindex("lo");
|
||||
assert_se(if_loopback > 0);
|
||||
|
||||
|
@ -114,7 +114,7 @@ static void netdev_cancel_callbacks(NetDev *netdev) {
|
||||
if (!netdev)
|
||||
return;
|
||||
|
||||
rtnl_message_new_synthetic_error(-ENODEV, 0, &m);
|
||||
rtnl_message_new_synthetic_error(netdev->manager->rtnl, -ENODEV, 0, &m);
|
||||
|
||||
while ((callback = netdev->callbacks)) {
|
||||
if (m) {
|
||||
@ -322,7 +322,7 @@ int netdev_enslave(NetDev *netdev, Link *link, sd_netlink_message_handler_t call
|
||||
} else if (IN_SET(netdev->state, NETDEV_STATE_LINGER, NETDEV_STATE_FAILED)) {
|
||||
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
|
||||
|
||||
r = rtnl_message_new_synthetic_error(-ENODEV, 0, &m);
|
||||
r = rtnl_message_new_synthetic_error(netdev->manager->rtnl, -ENODEV, 0, &m);
|
||||
if (r >= 0)
|
||||
callback(netdev->manager->rtnl, m, link);
|
||||
} else {
|
||||
|
@ -912,6 +912,26 @@ static int systemd_netlink_fd(void) {
|
||||
return rtnl_fd;
|
||||
}
|
||||
|
||||
static int manager_connect_genl(Manager *m) {
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
|
||||
r = sd_genl_socket_open(&m->genl);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_netlink_inc_rcvbuf(m->genl, RCVBUF_SIZE);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_netlink_attach_event(m->genl, m->event, 0);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int manager_connect_rtnl(Manager *m) {
|
||||
int fd, r;
|
||||
|
||||
@ -1256,6 +1276,10 @@ int manager_new(Manager **ret, sd_event *event) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = manager_connect_genl(m);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = manager_connect_udev(m);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@ -1266,6 +1290,14 @@ int manager_new(Manager **ret, sd_event *event) {
|
||||
|
||||
LIST_HEAD_INIT(m->networks);
|
||||
|
||||
r = sd_resolve_default(&m->resolve);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_resolve_attach_event(m->resolve, m->event, 0);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = setup_default_address_pool(m);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@ -1315,6 +1347,8 @@ void manager_free(Manager *m) {
|
||||
sd_netlink_unref(m->rtnl);
|
||||
sd_event_unref(m->event);
|
||||
|
||||
sd_resolve_unref(m->resolve);
|
||||
|
||||
sd_event_source_unref(m->udev_event_source);
|
||||
udev_monitor_unref(m->udev_monitor);
|
||||
udev_unref(m->udev);
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "sd-bus.h"
|
||||
#include "sd-event.h"
|
||||
#include "sd-netlink.h"
|
||||
#include "sd-resolve.h"
|
||||
#include "udev.h"
|
||||
|
||||
#include "dhcp-identifier.h"
|
||||
@ -39,7 +40,10 @@ extern const char* const network_dirs[];
|
||||
|
||||
struct Manager {
|
||||
sd_netlink *rtnl;
|
||||
/* lazy initialized */
|
||||
sd_netlink *genl;
|
||||
sd_event *event;
|
||||
sd_resolve *resolve;
|
||||
sd_event_source *bus_retry_event_source;
|
||||
sd_bus *bus;
|
||||
sd_bus_slot *prepare_for_sleep_slot;
|
||||
|
@ -34,7 +34,9 @@
|
||||
_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 enum {SD_GENL_ID_CTRL} sd_genl_family;
|
||||
|
||||
/* callback */
|
||||
|
||||
@ -94,6 +96,9 @@ int sd_netlink_message_read_in6_addr(sd_netlink_message *m, unsigned short type,
|
||||
int sd_netlink_message_enter_container(sd_netlink_message *m, unsigned short type);
|
||||
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_message *sd_netlink_message_next(sd_netlink_message *m);
|
||||
@ -177,6 +182,10 @@ int sd_rtnl_message_routing_policy_rule_get_rtm_type(sd_netlink_message *m, unsi
|
||||
_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_netlink, sd_netlink_unref);
|
||||
_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_netlink_message, sd_netlink_message_unref);
|
||||
|
||||
/* genl */
|
||||
int sd_genl_socket_open(sd_netlink **nl);
|
||||
int sd_genl_message_new(sd_netlink *nl, sd_genl_family family, uint8_t cmd, sd_netlink_message **m);
|
||||
|
||||
_SD_END_DECLARATIONS;
|
||||
|
||||
#endif
|
||||
|
Loading…
x
Reference in New Issue
Block a user