Skip to content

Commit e5c4350

Browse files
committed
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.
1 parent 1fa1329 commit e5c4350

File tree

3 files changed

+88
-26
lines changed

3 files changed

+88
-26
lines changed

src/libsystemd/sd-rtnl/rtnl-message.c

Lines changed: 61 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ struct sd_rtnl_message {
4545
#define GET_CONTAINER(m, i) (i < (m)->n_containers ? (struct rtattr*)((uint8_t*)(m)->hdr + (m)->container_offsets[i]) : NULL)
4646
#define NEXT_RTA(m) ((struct rtattr*)((uint8_t*)(m)->hdr + (m)->next_rta_offset))
4747
#define UPDATE_RTA(m, new) (m)->next_rta_offset = (uint8_t*)(new) - (uint8_t*)(m)->hdr;
48+
#define PUSH_CONTAINER(m, new) (m)->container_offsets[(m)->n_containers ++] = (uint8_t*)(new) - (uint8_t*)(m)->hdr;
4849

4950
static int message_new(sd_rtnl_message **ret, size_t initial_size) {
5051
sd_rtnl_message *m;
@@ -378,6 +379,7 @@ static int add_rtattr(sd_rtnl_message *m, unsigned short type, const void *data,
378379

379380
assert(m);
380381
assert(m->hdr);
382+
assert(!m->sealed);
381383
assert(NLMSG_ALIGN(m->hdr->nlmsg_len) == m->hdr->nlmsg_len);
382384
assert(!data || data_length > 0);
383385
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
428430
int r;
429431

430432
assert_return(m, -EINVAL);
433+
assert_return(!m->sealed, -EPERM);
431434
assert_return(data, -EINVAL);
432435

433436
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
477480
int r;
478481

479482
assert_return(m, -EINVAL);
483+
assert_return(!m->sealed, -EPERM);
480484

481485
r = sd_rtnl_message_get_type(m, &rtm_type);
482486
if (r < 0)
@@ -512,6 +516,7 @@ int sd_rtnl_message_append_u32(sd_rtnl_message *m, unsigned short type, uint32_t
512516
int r;
513517

514518
assert_return(m, -EINVAL);
519+
assert_return(!m->sealed, -EPERM);
515520

516521
r = sd_rtnl_message_get_type(m, &rtm_type);
517522
if (r < 0)
@@ -563,6 +568,7 @@ int sd_rtnl_message_append_in_addr(sd_rtnl_message *m, unsigned short type, cons
563568
int r;
564569

565570
assert_return(m, -EINVAL);
571+
assert_return(!m->sealed, -EPERM);
566572
assert_return(data, -EINVAL);
567573

568574
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
624630
int r;
625631

626632
assert_return(m, -EINVAL);
633+
assert_return(!m->sealed, -EPERM);
627634
assert_return(data, -EINVAL);
628635

629636
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
682689
int r;
683690

684691
assert_return(m, -EINVAL);
692+
assert_return(!m->sealed, -EPERM);
685693
assert_return(data, -EINVAL);
686694

687695
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) {
714722
uint16_t rtm_type;
715723

716724
assert_return(m, -EINVAL);
725+
assert_return(!m->sealed, -EPERM);
717726

718727
sd_rtnl_message_get_type(m, &rtm_type);
719728

@@ -732,6 +741,7 @@ int sd_rtnl_message_open_container(sd_rtnl_message *m, unsigned short type) {
732741

733742
int sd_rtnl_message_close_container(sd_rtnl_message *m) {
734743
assert_return(m, -EINVAL);
744+
assert_return(!m->sealed, -EPERM);
735745
assert_return(m->n_containers > 0, -EINVAL);
736746

737747
m->n_containers --;
@@ -744,34 +754,57 @@ int sd_rtnl_message_read(sd_rtnl_message *m, unsigned short *type, void **data)
744754
uint16_t rtm_type;
745755
int r;
746756

747-
assert(m);
748-
assert(m->next_rta_offset);
749-
assert(type);
750-
assert(data);
757+
assert_return(m, -EINVAL);
758+
assert_return(m->sealed, -EPERM);
759+
assert_return(m->next_rta_offset, -EINVAL);
760+
assert_return(type, -EINVAL);
761+
assert_return(data, -EINVAL);
751762

752-
remaining_size = m->hdr->nlmsg_len - m->next_rta_offset;
763+
/* only read until the end of the current container */
764+
if (m->n_containers)
765+
remaining_size = GET_CONTAINER(m, m->n_containers - 1)->rta_len -
766+
(m->next_rta_offset -
767+
m->container_offsets[m->n_containers - 1]);
768+
else
769+
remaining_size = m->hdr->nlmsg_len - m->next_rta_offset;
753770

754771
if (!RTA_OK(NEXT_RTA(m), remaining_size))
755772
return 0;
756773

757-
/* make sure we don't try to read a container
758-
* TODO: add support for entering containers for reading */
774+
/* if we read a container, enter it and return its type */
759775
r = sd_rtnl_message_get_type(m, &rtm_type);
760776
if (r < 0)
761777
return r;
762778

763-
if (message_type_is_link(rtm_type) &&
764-
NEXT_RTA(m)->rta_type == IFLA_LINKINFO)
765-
return -EINVAL;
766-
767-
*data = RTA_DATA(NEXT_RTA(m));
768779
*type = NEXT_RTA(m)->rta_type;
769780

770-
UPDATE_RTA(m, RTA_NEXT(NEXT_RTA(m), remaining_size));
781+
if (message_type_is_link(rtm_type) &&
782+
((m->n_containers == 0 &&
783+
NEXT_RTA(m)->rta_type == IFLA_LINKINFO) ||
784+
(m->n_containers == 1 &&
785+
GET_CONTAINER(m, 0)->rta_type == IFLA_LINKINFO &&
786+
NEXT_RTA(m)->rta_type == IFLA_INFO_DATA))) {
787+
*data = NULL;
788+
PUSH_CONTAINER(m, NEXT_RTA(m));
789+
UPDATE_RTA(m, RTA_DATA(NEXT_RTA(m)));
790+
} else {
791+
*data = RTA_DATA(NEXT_RTA(m));
792+
UPDATE_RTA(m, RTA_NEXT(NEXT_RTA(m), remaining_size));
793+
}
771794

772795
return 1;
773796
}
774797

798+
int sd_rtnl_message_exit_container(sd_rtnl_message *m) {
799+
assert_return(m, -EINVAL);
800+
assert_return(m->sealed, -EINVAL);
801+
assert_return(m->n_containers > 0, -EINVAL);
802+
803+
m->n_containers --;
804+
805+
return 0;
806+
}
807+
775808
uint32_t message_get_serial(sd_rtnl_message *m) {
776809
assert(m);
777810
assert(m->hdr);
@@ -794,16 +827,23 @@ int sd_rtnl_message_get_errno(sd_rtnl_message *m) {
794827
}
795828

796829
int message_seal(sd_rtnl *nl, sd_rtnl_message *m) {
797-
assert(nl);
830+
int r;
831+
798832
assert(m);
799833
assert(m->hdr);
800834

801835
if (m->sealed)
802836
return -EPERM;
803837

804-
m->hdr->nlmsg_seq = nl->serial++;
838+
if (nl)
839+
m->hdr->nlmsg_seq = nl->serial++;
840+
805841
m->sealed = true;
806842

843+
r = sd_rtnl_message_rewind(m);
844+
if (r < 0)
845+
return r;
846+
807847
return 0;
808848
}
809849

@@ -876,6 +916,9 @@ int socket_read_message(sd_rtnl *nl, sd_rtnl_message **ret) {
876916
if (r < 0)
877917
return r;
878918

919+
/* don't allow sealing/appending to received messages */
920+
m->sealed = true;
921+
879922
addr_len = sizeof(addr);
880923

881924
k = recvfrom(nl->fd, m->hdr, need,
@@ -961,6 +1004,7 @@ int sd_rtnl_message_rewind(sd_rtnl_message *m) {
9611004
struct rtmsg *rtm;
9621005

9631006
assert_return(m, -EINVAL);
1007+
assert_return(m->sealed, -EPERM);
9641008
assert_return(m->hdr, -EINVAL);
9651009

9661010
switch(m->hdr->nlmsg_type) {
@@ -990,5 +1034,7 @@ int sd_rtnl_message_rewind(sd_rtnl_message *m) {
9901034
return -ENOTSUP;
9911035
}
9921036

1037+
m->n_containers = 0;
1038+
9931039
return 0;
9941040
}

src/libsystemd/sd-rtnl/test-rtnl.c

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include "sd-rtnl.h"
2828
#include "socket-util.h"
2929
#include "rtnl-util.h"
30+
#include "rtnl-internal.h"
3031
#include "event-util.h"
3132

3233
static void test_link_configure(sd_rtnl *rtnl, int ifindex) {
@@ -42,6 +43,8 @@ static void test_link_configure(sd_rtnl *rtnl, int ifindex) {
4243
assert(sd_rtnl_message_append_ether_addr(message, IFLA_ADDRESS, ether_aton(mac)) >= 0);
4344
assert(sd_rtnl_message_append_u32(message, IFLA_MTU, mtu) >= 0);
4445

46+
assert(sd_rtnl_call(rtnl, message, 0, NULL) == 1);
47+
4548
assert(sd_rtnl_message_read(message, &type, &data) > 0);
4649
assert(type == IFLA_IFNAME);
4750
assert(streq(name, (char *) data));
@@ -53,8 +56,6 @@ static void test_link_configure(sd_rtnl *rtnl, int ifindex) {
5356
assert(sd_rtnl_message_read(message, &type, &data) > 0);
5457
assert(type == IFLA_MTU);
5558
assert(mtu == *(unsigned int *) data);
56-
57-
assert(sd_rtnl_call(rtnl, message, 0, NULL) == 1);
5859
}
5960

6061
static void test_route(void) {
@@ -85,6 +86,8 @@ static void test_route(void) {
8586
return;
8687
}
8788

89+
assert(message_seal(NULL, req) >= 0);
90+
8891
assert(sd_rtnl_message_read(req, &type, &data) > 0);
8992
assert(type == RTA_GATEWAY);
9093
assert(((struct in_addr *)data)->s_addr == addr.s_addr);
@@ -224,15 +227,26 @@ static void test_container(void) {
224227
assert(sd_rtnl_message_close_container(m) >= 0);
225228
assert(sd_rtnl_message_close_container(m) == -EINVAL);
226229

227-
assert(sd_rtnl_message_read(m, &type, &data) == -EINVAL);
230+
assert(message_seal(NULL, m) >= 0);
228231

229-
/* TODO: add support for entering containers
230-
assert(sd_rtnl_message_read(m, &type, &data) > 0);
232+
assert(sd_rtnl_message_read(m, &type, &data) >= 0);
233+
assert(type == IFLA_LINKINFO);
234+
assert(data == NULL);
235+
assert(sd_rtnl_message_read(m, &type, &data) >= 0);
231236
assert(type == IFLA_INFO_KIND);
232-
assert(streq("kind", (char *) data));
233-
234-
assert(sd_rtnl_message_read(m, &type, &data) == 0);
235-
*/
237+
assert(streq("kind", (char *)data));
238+
assert(sd_rtnl_message_read(m, &type, &data) >= 0);
239+
assert(type == IFLA_INFO_DATA);
240+
assert(data == NULL);
241+
assert(sd_rtnl_message_read(m, &type, &data) >= 0);
242+
assert(type == IFLA_VLAN_ID);
243+
assert(*(uint16_t *)data == 100);
244+
assert(sd_rtnl_message_exit_container(m) >= 0);
245+
assert(sd_rtnl_message_read(m, &type, &data) >= 0);
246+
assert(type == IFLA_INFO_KIND);
247+
assert(streq("kind", (char *)data));
248+
assert(sd_rtnl_message_exit_container(m) >= 0);
249+
assert(sd_rtnl_message_exit_container(m) == -EINVAL);
236250
}
237251

238252
static void test_match(void) {
@@ -286,7 +300,7 @@ int main(void) {
286300
assert(sd_rtnl_message_get_type(m, &type) >= 0);
287301
assert(type == RTM_GETLINK);
288302

289-
assert(sd_rtnl_message_read(m, &type, &data) == 0);
303+
assert(sd_rtnl_message_read(m, &type, &data) == -EPERM);
290304

291305
assert(sd_rtnl_call(rtnl, m, 0, &r) == 1);
292306
assert(sd_rtnl_message_get_type(r, &type) >= 0);
@@ -303,14 +317,15 @@ int main(void) {
303317
assert(m);
304318

305319
assert(sd_rtnl_message_append_u32(m, IFLA_MTU, mtu) >= 0);
320+
assert(sd_rtnl_message_read(m, &type, (void **) &mtu_reply) == -EPERM);
321+
assert(sd_rtnl_call(rtnl, m, -1, &r) == 1);
306322
assert(sd_rtnl_message_read(m, &type, (void **) &mtu_reply) == 1);
307323

308324
assert(type == IFLA_MTU);
309325
assert(*mtu_reply == 0);
310326

311327
assert(sd_rtnl_message_read(m, &type, &data) == 0);
312328

313-
assert(sd_rtnl_call(rtnl, m, -1, &r) == 1);
314329
while (sd_rtnl_message_read(r, &type, &data) > 0) {
315330
switch (type) {
316331
// case IFLA_MTU:

src/systemd/sd-rtnl.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ int sd_rtnl_message_open_container(sd_rtnl_message *m, unsigned short type);
105105
int sd_rtnl_message_close_container(sd_rtnl_message *m);
106106

107107
int sd_rtnl_message_read(sd_rtnl_message *m, unsigned short *type, void **data);
108+
int sd_rtnl_message_exit_container(sd_rtnl_message *m);
108109

109110
int sd_rtnl_message_rewind(sd_rtnl_message *m);
110111

0 commit comments

Comments
 (0)