mirror of
https://github.com/systemd/systemd.git
synced 2026-08-03 06:30:30 +00:00
sd-rtnl: add support for reading containers
Also insist on messages being sealed before reading them. In other words we don't allow interleaving of reading and appending to messages.
This commit is contained in:
@@ -45,6 +45,7 @@ struct sd_rtnl_message {
|
||||
#define GET_CONTAINER(m, i) (i < (m)->n_containers ? (struct rtattr*)((uint8_t*)(m)->hdr + (m)->container_offsets[i]) : NULL)
|
||||
#define NEXT_RTA(m) ((struct rtattr*)((uint8_t*)(m)->hdr + (m)->next_rta_offset))
|
||||
#define UPDATE_RTA(m, new) (m)->next_rta_offset = (uint8_t*)(new) - (uint8_t*)(m)->hdr;
|
||||
#define PUSH_CONTAINER(m, new) (m)->container_offsets[(m)->n_containers ++] = (uint8_t*)(new) - (uint8_t*)(m)->hdr;
|
||||
|
||||
static int message_new(sd_rtnl_message **ret, size_t initial_size) {
|
||||
sd_rtnl_message *m;
|
||||
@@ -378,6 +379,7 @@ static int add_rtattr(sd_rtnl_message *m, unsigned short type, const void *data,
|
||||
|
||||
assert(m);
|
||||
assert(m->hdr);
|
||||
assert(!m->sealed);
|
||||
assert(NLMSG_ALIGN(m->hdr->nlmsg_len) == m->hdr->nlmsg_len);
|
||||
assert(!data || data_length > 0);
|
||||
assert(data || m->n_containers < RTNL_CONTAINER_DEPTH);
|
||||
@@ -428,6 +430,7 @@ int sd_rtnl_message_append_string(sd_rtnl_message *m, unsigned short type, const
|
||||
int r;
|
||||
|
||||
assert_return(m, -EINVAL);
|
||||
assert_return(!m->sealed, -EPERM);
|
||||
assert_return(data, -EINVAL);
|
||||
|
||||
r = sd_rtnl_message_get_type(m, &rtm_type);
|
||||
@@ -477,6 +480,7 @@ int sd_rtnl_message_append_u16(sd_rtnl_message *m, unsigned short type, uint16_t
|
||||
int r;
|
||||
|
||||
assert_return(m, -EINVAL);
|
||||
assert_return(!m->sealed, -EPERM);
|
||||
|
||||
r = sd_rtnl_message_get_type(m, &rtm_type);
|
||||
if (r < 0)
|
||||
@@ -512,6 +516,7 @@ int sd_rtnl_message_append_u32(sd_rtnl_message *m, unsigned short type, uint32_t
|
||||
int r;
|
||||
|
||||
assert_return(m, -EINVAL);
|
||||
assert_return(!m->sealed, -EPERM);
|
||||
|
||||
r = sd_rtnl_message_get_type(m, &rtm_type);
|
||||
if (r < 0)
|
||||
@@ -563,6 +568,7 @@ int sd_rtnl_message_append_in_addr(sd_rtnl_message *m, unsigned short type, cons
|
||||
int r;
|
||||
|
||||
assert_return(m, -EINVAL);
|
||||
assert_return(!m->sealed, -EPERM);
|
||||
assert_return(data, -EINVAL);
|
||||
|
||||
r = sd_rtnl_message_get_type(m, &rtm_type);
|
||||
@@ -624,6 +630,7 @@ int sd_rtnl_message_append_in6_addr(sd_rtnl_message *m, unsigned short type, con
|
||||
int r;
|
||||
|
||||
assert_return(m, -EINVAL);
|
||||
assert_return(!m->sealed, -EPERM);
|
||||
assert_return(data, -EINVAL);
|
||||
|
||||
r = sd_rtnl_message_get_type(m, &rtm_type);
|
||||
@@ -682,6 +689,7 @@ int sd_rtnl_message_append_ether_addr(sd_rtnl_message *m, unsigned short type, c
|
||||
int r;
|
||||
|
||||
assert_return(m, -EINVAL);
|
||||
assert_return(!m->sealed, -EPERM);
|
||||
assert_return(data, -EINVAL);
|
||||
|
||||
sd_rtnl_message_get_type(m, &rtm_type);
|
||||
@@ -714,6 +722,7 @@ int sd_rtnl_message_open_container(sd_rtnl_message *m, unsigned short type) {
|
||||
uint16_t rtm_type;
|
||||
|
||||
assert_return(m, -EINVAL);
|
||||
assert_return(!m->sealed, -EPERM);
|
||||
|
||||
sd_rtnl_message_get_type(m, &rtm_type);
|
||||
|
||||
@@ -732,6 +741,7 @@ int sd_rtnl_message_open_container(sd_rtnl_message *m, unsigned short type) {
|
||||
|
||||
int sd_rtnl_message_close_container(sd_rtnl_message *m) {
|
||||
assert_return(m, -EINVAL);
|
||||
assert_return(!m->sealed, -EPERM);
|
||||
assert_return(m->n_containers > 0, -EINVAL);
|
||||
|
||||
m->n_containers --;
|
||||
@@ -744,34 +754,57 @@ int sd_rtnl_message_read(sd_rtnl_message *m, unsigned short *type, void **data)
|
||||
uint16_t rtm_type;
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
assert(m->next_rta_offset);
|
||||
assert(type);
|
||||
assert(data);
|
||||
assert_return(m, -EINVAL);
|
||||
assert_return(m->sealed, -EPERM);
|
||||
assert_return(m->next_rta_offset, -EINVAL);
|
||||
assert_return(type, -EINVAL);
|
||||
assert_return(data, -EINVAL);
|
||||
|
||||
remaining_size = m->hdr->nlmsg_len - m->next_rta_offset;
|
||||
/* only read until the end of the current container */
|
||||
if (m->n_containers)
|
||||
remaining_size = GET_CONTAINER(m, m->n_containers - 1)->rta_len -
|
||||
(m->next_rta_offset -
|
||||
m->container_offsets[m->n_containers - 1]);
|
||||
else
|
||||
remaining_size = m->hdr->nlmsg_len - m->next_rta_offset;
|
||||
|
||||
if (!RTA_OK(NEXT_RTA(m), remaining_size))
|
||||
return 0;
|
||||
|
||||
/* make sure we don't try to read a container
|
||||
* TODO: add support for entering containers for reading */
|
||||
/* if we read a container, enter it and return its type */
|
||||
r = sd_rtnl_message_get_type(m, &rtm_type);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (message_type_is_link(rtm_type) &&
|
||||
NEXT_RTA(m)->rta_type == IFLA_LINKINFO)
|
||||
return -EINVAL;
|
||||
|
||||
*data = RTA_DATA(NEXT_RTA(m));
|
||||
*type = NEXT_RTA(m)->rta_type;
|
||||
|
||||
UPDATE_RTA(m, RTA_NEXT(NEXT_RTA(m), remaining_size));
|
||||
if (message_type_is_link(rtm_type) &&
|
||||
((m->n_containers == 0 &&
|
||||
NEXT_RTA(m)->rta_type == IFLA_LINKINFO) ||
|
||||
(m->n_containers == 1 &&
|
||||
GET_CONTAINER(m, 0)->rta_type == IFLA_LINKINFO &&
|
||||
NEXT_RTA(m)->rta_type == IFLA_INFO_DATA))) {
|
||||
*data = NULL;
|
||||
PUSH_CONTAINER(m, NEXT_RTA(m));
|
||||
UPDATE_RTA(m, RTA_DATA(NEXT_RTA(m)));
|
||||
} else {
|
||||
*data = RTA_DATA(NEXT_RTA(m));
|
||||
UPDATE_RTA(m, RTA_NEXT(NEXT_RTA(m), remaining_size));
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int sd_rtnl_message_exit_container(sd_rtnl_message *m) {
|
||||
assert_return(m, -EINVAL);
|
||||
assert_return(m->sealed, -EINVAL);
|
||||
assert_return(m->n_containers > 0, -EINVAL);
|
||||
|
||||
m->n_containers --;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t message_get_serial(sd_rtnl_message *m) {
|
||||
assert(m);
|
||||
assert(m->hdr);
|
||||
@@ -794,16 +827,23 @@ int sd_rtnl_message_get_errno(sd_rtnl_message *m) {
|
||||
}
|
||||
|
||||
int message_seal(sd_rtnl *nl, sd_rtnl_message *m) {
|
||||
assert(nl);
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
assert(m->hdr);
|
||||
|
||||
if (m->sealed)
|
||||
return -EPERM;
|
||||
|
||||
m->hdr->nlmsg_seq = nl->serial++;
|
||||
if (nl)
|
||||
m->hdr->nlmsg_seq = nl->serial++;
|
||||
|
||||
m->sealed = true;
|
||||
|
||||
r = sd_rtnl_message_rewind(m);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -876,6 +916,9 @@ int socket_read_message(sd_rtnl *nl, sd_rtnl_message **ret) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* don't allow sealing/appending to received messages */
|
||||
m->sealed = true;
|
||||
|
||||
addr_len = sizeof(addr);
|
||||
|
||||
k = recvfrom(nl->fd, m->hdr, need,
|
||||
@@ -961,6 +1004,7 @@ int sd_rtnl_message_rewind(sd_rtnl_message *m) {
|
||||
struct rtmsg *rtm;
|
||||
|
||||
assert_return(m, -EINVAL);
|
||||
assert_return(m->sealed, -EPERM);
|
||||
assert_return(m->hdr, -EINVAL);
|
||||
|
||||
switch(m->hdr->nlmsg_type) {
|
||||
@@ -990,5 +1034,7 @@ int sd_rtnl_message_rewind(sd_rtnl_message *m) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
m->n_containers = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "sd-rtnl.h"
|
||||
#include "socket-util.h"
|
||||
#include "rtnl-util.h"
|
||||
#include "rtnl-internal.h"
|
||||
#include "event-util.h"
|
||||
|
||||
static void test_link_configure(sd_rtnl *rtnl, int ifindex) {
|
||||
@@ -42,6 +43,8 @@ static void test_link_configure(sd_rtnl *rtnl, int ifindex) {
|
||||
assert(sd_rtnl_message_append_ether_addr(message, IFLA_ADDRESS, ether_aton(mac)) >= 0);
|
||||
assert(sd_rtnl_message_append_u32(message, IFLA_MTU, mtu) >= 0);
|
||||
|
||||
assert(sd_rtnl_call(rtnl, message, 0, NULL) == 1);
|
||||
|
||||
assert(sd_rtnl_message_read(message, &type, &data) > 0);
|
||||
assert(type == IFLA_IFNAME);
|
||||
assert(streq(name, (char *) data));
|
||||
@@ -53,8 +56,6 @@ static void test_link_configure(sd_rtnl *rtnl, int ifindex) {
|
||||
assert(sd_rtnl_message_read(message, &type, &data) > 0);
|
||||
assert(type == IFLA_MTU);
|
||||
assert(mtu == *(unsigned int *) data);
|
||||
|
||||
assert(sd_rtnl_call(rtnl, message, 0, NULL) == 1);
|
||||
}
|
||||
|
||||
static void test_route(void) {
|
||||
@@ -85,6 +86,8 @@ static void test_route(void) {
|
||||
return;
|
||||
}
|
||||
|
||||
assert(message_seal(NULL, req) >= 0);
|
||||
|
||||
assert(sd_rtnl_message_read(req, &type, &data) > 0);
|
||||
assert(type == RTA_GATEWAY);
|
||||
assert(((struct in_addr *)data)->s_addr == addr.s_addr);
|
||||
@@ -224,15 +227,26 @@ static void test_container(void) {
|
||||
assert(sd_rtnl_message_close_container(m) >= 0);
|
||||
assert(sd_rtnl_message_close_container(m) == -EINVAL);
|
||||
|
||||
assert(sd_rtnl_message_read(m, &type, &data) == -EINVAL);
|
||||
assert(message_seal(NULL, m) >= 0);
|
||||
|
||||
/* TODO: add support for entering containers
|
||||
assert(sd_rtnl_message_read(m, &type, &data) > 0);
|
||||
assert(sd_rtnl_message_read(m, &type, &data) >= 0);
|
||||
assert(type == IFLA_LINKINFO);
|
||||
assert(data == NULL);
|
||||
assert(sd_rtnl_message_read(m, &type, &data) >= 0);
|
||||
assert(type == IFLA_INFO_KIND);
|
||||
assert(streq("kind", (char *) data));
|
||||
|
||||
assert(sd_rtnl_message_read(m, &type, &data) == 0);
|
||||
*/
|
||||
assert(streq("kind", (char *)data));
|
||||
assert(sd_rtnl_message_read(m, &type, &data) >= 0);
|
||||
assert(type == IFLA_INFO_DATA);
|
||||
assert(data == NULL);
|
||||
assert(sd_rtnl_message_read(m, &type, &data) >= 0);
|
||||
assert(type == IFLA_VLAN_ID);
|
||||
assert(*(uint16_t *)data == 100);
|
||||
assert(sd_rtnl_message_exit_container(m) >= 0);
|
||||
assert(sd_rtnl_message_read(m, &type, &data) >= 0);
|
||||
assert(type == IFLA_INFO_KIND);
|
||||
assert(streq("kind", (char *)data));
|
||||
assert(sd_rtnl_message_exit_container(m) >= 0);
|
||||
assert(sd_rtnl_message_exit_container(m) == -EINVAL);
|
||||
}
|
||||
|
||||
static void test_match(void) {
|
||||
@@ -286,7 +300,7 @@ int main(void) {
|
||||
assert(sd_rtnl_message_get_type(m, &type) >= 0);
|
||||
assert(type == RTM_GETLINK);
|
||||
|
||||
assert(sd_rtnl_message_read(m, &type, &data) == 0);
|
||||
assert(sd_rtnl_message_read(m, &type, &data) == -EPERM);
|
||||
|
||||
assert(sd_rtnl_call(rtnl, m, 0, &r) == 1);
|
||||
assert(sd_rtnl_message_get_type(r, &type) >= 0);
|
||||
@@ -303,6 +317,8 @@ int main(void) {
|
||||
assert(m);
|
||||
|
||||
assert(sd_rtnl_message_append_u32(m, IFLA_MTU, mtu) >= 0);
|
||||
assert(sd_rtnl_message_read(m, &type, (void **) &mtu_reply) == -EPERM);
|
||||
assert(sd_rtnl_call(rtnl, m, -1, &r) == 1);
|
||||
assert(sd_rtnl_message_read(m, &type, (void **) &mtu_reply) == 1);
|
||||
|
||||
assert(type == IFLA_MTU);
|
||||
@@ -310,7 +326,6 @@ int main(void) {
|
||||
|
||||
assert(sd_rtnl_message_read(m, &type, &data) == 0);
|
||||
|
||||
assert(sd_rtnl_call(rtnl, m, -1, &r) == 1);
|
||||
while (sd_rtnl_message_read(r, &type, &data) > 0) {
|
||||
switch (type) {
|
||||
// case IFLA_MTU:
|
||||
|
||||
@@ -105,6 +105,7 @@ int sd_rtnl_message_open_container(sd_rtnl_message *m, unsigned short type);
|
||||
int sd_rtnl_message_close_container(sd_rtnl_message *m);
|
||||
|
||||
int sd_rtnl_message_read(sd_rtnl_message *m, unsigned short *type, void **data);
|
||||
int sd_rtnl_message_exit_container(sd_rtnl_message *m);
|
||||
|
||||
int sd_rtnl_message_rewind(sd_rtnl_message *m);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user