chiark / gitweb /
sd-rtnl: add sd_rtnl_message_enter_container()
[elogind.git] / src / libsystemd / sd-rtnl / test-rtnl.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2013 Tom Gundersen <teg@jklm.no>
7
8   systemd is free software; you can redistribute it and/or modify it
9   under the terms of the GNU Lesser General Public License as published by
10   the Free Software Foundation; either version 2.1 of the License, or
11   (at your option) any later version.
12
13   systemd is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   Lesser General Public License for more details.
17
18   You should have received a copy of the GNU Lesser General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <netinet/ether.h>
23
24 #include "util.h"
25 #include "macro.h"
26 #include "sd-rtnl.h"
27 #include "socket-util.h"
28 #include "rtnl-util.h"
29 #include "event-util.h"
30 #include "missing.h"
31 #include "rtnl-internal.h"
32
33 static void test_link_configure(sd_rtnl *rtnl, int ifindex) {
34         _cleanup_rtnl_message_unref_ sd_rtnl_message *message;
35         const char *mac = "98:fe:94:3f:c6:18", *name = "test";
36         unsigned int mtu = 1450, mtu_out;
37         char *name_out;
38         struct ether_addr mac_out;
39
40         /* we'd really like to test NEWLINK, but let's not mess with the running kernel */
41         assert_se(sd_rtnl_message_new_link(rtnl, &message, RTM_GETLINK, ifindex) >= 0);
42         assert_se(sd_rtnl_message_append_string(message, IFLA_IFNAME, name) >= 0);
43         assert_se(sd_rtnl_message_append_ether_addr(message, IFLA_ADDRESS, ether_aton(mac)) >= 0);
44         assert_se(sd_rtnl_message_append_u32(message, IFLA_MTU, mtu) >= 0);
45
46         assert_se(sd_rtnl_call(rtnl, message, 0, NULL) == 1);
47         assert_se(sd_rtnl_message_rewind(message) >= 0);
48
49         assert_se(sd_rtnl_message_read_string(message, IFLA_IFNAME, &name_out) >= 0);
50         assert_se(streq(name, name_out));
51
52         assert_se(sd_rtnl_message_read_ether_addr(message, IFLA_ADDRESS, &mac_out) >= 0);
53         assert_se(streq(mac, ether_ntoa(&mac_out)));
54
55         assert_se(sd_rtnl_message_read_u32(message, IFLA_MTU, &mtu_out) >= 0);
56         assert_se(mtu == mtu_out);
57 }
58
59 static void test_link_get(sd_rtnl *rtnl, int ifindex) {
60         sd_rtnl_message *m;
61         sd_rtnl_message *r;
62         unsigned int mtu = 1500;
63         char *str_data;
64         uint8_t u8_data;
65         uint32_t u32_data;
66         struct ether_addr eth_data;
67
68         assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_GETLINK, ifindex) >= 0);
69         assert_se(m);
70
71         /* u8 test cases  */
72         assert_se(sd_rtnl_message_append_u8(m, IFLA_CARRIER, 0) >= 0);
73         assert_se(sd_rtnl_message_append_u8(m, IFLA_OPERSTATE, 0) >= 0);
74         assert_se(sd_rtnl_message_append_u8(m, IFLA_LINKMODE, 0) >= 0);
75
76         /* u32 test cases */
77         assert_se(sd_rtnl_message_append_u32(m, IFLA_MTU, mtu) >= 0);
78         assert_se(sd_rtnl_message_append_u32(m, IFLA_GROUP, 0) >= 0);
79         assert_se(sd_rtnl_message_append_u32(m, IFLA_TXQLEN, 0) >= 0);
80         assert_se(sd_rtnl_message_append_u32(m, IFLA_NUM_TX_QUEUES, 0) >= 0);
81         assert_se(sd_rtnl_message_append_u32(m, IFLA_NUM_RX_QUEUES, 0) >= 0);
82
83         assert_se(sd_rtnl_call(rtnl, m, -1, &r) == 1);
84
85         assert_se(sd_rtnl_message_read_string(r, IFLA_IFNAME, &str_data) == 0);
86
87         assert_se(sd_rtnl_message_read_u8(r, IFLA_CARRIER, &u8_data) == 0);
88         assert_se(sd_rtnl_message_read_u8(r, IFLA_OPERSTATE, &u8_data) == 0);
89         assert_se(sd_rtnl_message_read_u8(r, IFLA_LINKMODE, &u8_data) == 0);
90
91         assert_se(sd_rtnl_message_read_u32(r, IFLA_MTU, &u32_data) == 0);
92         assert_se(sd_rtnl_message_read_u32(r, IFLA_GROUP, &u32_data) == 0);
93         assert_se(sd_rtnl_message_read_u32(r, IFLA_TXQLEN, &u32_data) == 0);
94         assert_se(sd_rtnl_message_read_u32(r, IFLA_NUM_TX_QUEUES, &u32_data) == 0);
95         assert_se(sd_rtnl_message_read_u32(r, IFLA_NUM_RX_QUEUES, &u32_data) == 0);
96
97         assert_se(sd_rtnl_message_read_ether_addr(r, IFLA_ADDRESS, &eth_data) == 0);
98
99         assert_se(sd_rtnl_flush(rtnl) >= 0);
100         assert_se((m = sd_rtnl_message_unref(m)) == NULL);
101         assert_se((r = sd_rtnl_message_unref(r)) == NULL);
102 }
103
104
105 static void test_address_get(sd_rtnl *rtnl, int ifindex) {
106         sd_rtnl_message *m;
107         sd_rtnl_message *r;
108         struct in_addr in_data;
109         char *label;
110
111         assert_se(sd_rtnl_message_new_addr(rtnl, &m, RTM_GETADDR, ifindex, AF_INET) >= 0);
112         assert_se(m);
113
114         assert_se(sd_rtnl_call(rtnl, m, -1, &r) == 1);
115
116         assert_se(sd_rtnl_message_read_in_addr(r, IFA_LOCAL, &in_data) == 0);
117         assert_se(sd_rtnl_message_read_in_addr(r, IFA_ADDRESS, &in_data) == 0);
118         assert_se(sd_rtnl_message_read_string(r, IFA_LABEL, &label) == 0);
119
120         assert_se(sd_rtnl_flush(rtnl) >= 0);
121         assert_se((m = sd_rtnl_message_unref(m)) == NULL);
122         assert_se((r = sd_rtnl_message_unref(r)) == NULL);
123
124 }
125
126 static void test_route(void) {
127         _cleanup_rtnl_message_unref_ sd_rtnl_message *req;
128         struct rtmsg *rtm;
129         struct in_addr addr, addr_data;
130         uint32_t index = 2, u32_data;
131         int r;
132
133         r = sd_rtnl_message_new_route(NULL, &req, RTM_NEWROUTE, AF_INET);
134         if (r < 0) {
135                 log_error("Could not create RTM_NEWROUTE message: %s", strerror(-r));
136                 return;
137         }
138
139         addr.s_addr = htonl(INADDR_LOOPBACK);
140
141         r = sd_rtnl_message_append_in_addr(req, RTA_GATEWAY, &addr);
142         if (r < 0) {
143                 log_error("Could not append RTA_GATEWAY attribute: %s", strerror(-r));
144                 return;
145         }
146
147         r = sd_rtnl_message_append_u32(req, RTA_OIF, index);
148         if (r < 0) {
149                 log_error("Could not append RTA_OIF attribute: %s", strerror(-r));
150                 return;
151         }
152
153         assert_se(sd_rtnl_message_rewind(req) >= 0);
154
155         assert_se(sd_rtnl_message_read_in_addr(req, RTA_GATEWAY, &addr_data) >= 0);
156         assert_se(addr_data.s_addr == addr.s_addr);
157
158         assert_se(sd_rtnl_message_read_u32(req, RTA_OIF, &u32_data) >= 0);
159         assert_se(u32_data == index);
160
161         rtm = NLMSG_DATA(req->hdr);
162         r = rtnl_message_parse(req,
163                                &req->rta_offset_tb,
164                                &req->rta_tb_size,
165                                RTA_MAX,
166                                RTM_RTA(rtm),
167                                RTM_PAYLOAD(req->hdr));
168
169         assert_se(sd_rtnl_message_read_u32(req, RTA_GATEWAY, &u32_data) == 0);
170         assert_se(sd_rtnl_message_read_u32(req, RTA_OIF, &u32_data) == 0);
171
172         assert_se((req = sd_rtnl_message_unref(req)) == NULL);
173 }
174
175 static void test_multiple(void) {
176         sd_rtnl *rtnl1, *rtnl2;
177
178         assert_se(sd_rtnl_open(&rtnl1, 0) >= 0);
179         assert_se(sd_rtnl_open(&rtnl2, 0) >= 0);
180
181         rtnl1 = sd_rtnl_unref(rtnl1);
182         rtnl2 = sd_rtnl_unref(rtnl2);
183 }
184
185 static int link_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
186         char *ifname = userdata, *data;
187
188         assert_se(rtnl);
189         assert_se(m);
190
191         log_info("got link info about %s", ifname);
192         free(ifname);
193
194         assert_se(sd_rtnl_message_read_string(m, IFLA_IFNAME, &data) >= 0);
195         assert_se(streq(data, "lo"));
196
197         return 1;
198 }
199
200 static void test_event_loop(int ifindex) {
201         _cleanup_event_unref_ sd_event *event = NULL;
202         _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
203         _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
204         char *ifname;
205
206         ifname = strdup("lo2");
207         assert_se(ifname);
208
209         assert_se(sd_rtnl_open(&rtnl, 0) >= 0);
210         assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_GETLINK, ifindex) >= 0);
211
212         assert_se(sd_rtnl_call_async(rtnl, m, &link_handler, ifname, 0, NULL) >= 0);
213
214         assert_se(sd_event_default(&event) >= 0);
215
216         assert_se(sd_rtnl_attach_event(rtnl, event, 0) >= 0);
217
218         assert_se(sd_event_run(event, 0) >= 0);
219
220         assert_se(sd_rtnl_detach_event(rtnl) >= 0);
221
222         assert_se((rtnl = sd_rtnl_unref(rtnl)) == NULL);
223 }
224
225 static int pipe_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
226         int *counter = userdata;
227         int r;
228
229         (*counter) --;
230
231         r = sd_rtnl_message_get_errno(m);
232
233         log_info("%d left in pipe. got reply: %s", *counter, strerror(-r));
234
235         assert_se(r >= 0);
236
237         return 1;
238 }
239
240 static void test_async(int ifindex) {
241         _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
242         _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL, *r = NULL;
243         uint32_t serial;
244         char *ifname;
245
246         ifname = strdup("lo");
247         assert_se(ifname);
248
249         assert_se(sd_rtnl_open(&rtnl, 0) >= 0);
250
251         assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_GETLINK, ifindex) >= 0);
252
253         assert_se(sd_rtnl_call_async(rtnl, m, &link_handler, ifname, 0, &serial) >= 0);
254
255         assert_se(sd_rtnl_wait(rtnl, 0) >= 0);
256         assert_se(sd_rtnl_process(rtnl, &r) >= 0);
257
258         assert_se((rtnl = sd_rtnl_unref(rtnl)) == NULL);
259 }
260
261 static void test_pipe(int ifindex) {
262         _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
263         _cleanup_rtnl_message_unref_ sd_rtnl_message *m1 = NULL, *m2 = NULL;
264         int counter = 0;
265
266         assert_se(sd_rtnl_open(&rtnl, 0) >= 0);
267
268         assert_se(sd_rtnl_message_new_link(rtnl, &m1, RTM_GETLINK, ifindex) >= 0);
269         assert_se(sd_rtnl_message_new_link(rtnl, &m2, RTM_GETLINK, ifindex) >= 0);
270
271         counter ++;
272         assert_se(sd_rtnl_call_async(rtnl, m1, &pipe_handler, &counter, 0, NULL) >= 0);
273
274         counter ++;
275         assert_se(sd_rtnl_call_async(rtnl, m2, &pipe_handler, &counter, 0, NULL) >= 0);
276
277         while (counter > 0) {
278                 assert_se(sd_rtnl_wait(rtnl, 0) >= 0);
279                 assert_se(sd_rtnl_process(rtnl, NULL) >= 0);
280         }
281
282         assert_se((rtnl = sd_rtnl_unref(rtnl)) == NULL);
283 }
284
285 static void test_container(void) {
286         _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
287         struct ifinfomsg *ifi;
288         uint16_t u16_data;
289         uint32_t u32_data;
290         char *string_data;
291         int r;
292
293         assert_se(sd_rtnl_message_new_link(NULL, &m, RTM_NEWLINK, 0) >= 0);
294
295         assert_se(sd_rtnl_message_open_container(m, IFLA_LINKINFO) >= 0);
296         assert_se(sd_rtnl_message_open_container(m, IFLA_LINKINFO) == -ENOTSUP);
297         assert_se(sd_rtnl_message_append_string(m, IFLA_INFO_KIND, "vlan") >= 0);
298         assert_se(sd_rtnl_message_open_container(m, IFLA_INFO_DATA) >= 0);
299         assert_se(sd_rtnl_message_open_container(m, IFLA_INFO_DATA) == -ENOTSUP);
300         assert_se(sd_rtnl_message_append_u16(m, IFLA_VLAN_ID, 100) >= 0);
301         assert_se(sd_rtnl_message_close_container(m) >= 0);
302         assert_se(sd_rtnl_message_append_string(m, IFLA_INFO_KIND, "vlan") >= 0);
303         assert_se(sd_rtnl_message_close_container(m) >= 0);
304         assert_se(sd_rtnl_message_close_container(m) == -EINVAL);
305
306         assert_se(sd_rtnl_message_rewind(m) >= 0);
307
308         assert_se(sd_rtnl_message_enter_container(m, IFLA_LINKINFO) >= 0);
309         assert_se(sd_rtnl_message_read_string(m, IFLA_INFO_KIND, &string_data) >= 0);
310         assert_se(streq("vlan", string_data));
311
312         assert_se(sd_rtnl_message_enter_container(m, IFLA_INFO_DATA) >= 0);
313         assert_se(sd_rtnl_message_read_u16(m, IFLA_VLAN_ID, &u16_data) >= 0);
314         assert_se(sd_rtnl_message_exit_container(m) >= 0);
315
316         assert_se(sd_rtnl_message_read_string(m, IFLA_INFO_KIND, &string_data) >= 0);
317         assert_se(streq("vlan", string_data));
318         assert_se(sd_rtnl_message_exit_container(m) >= 0);
319
320         ifi = NLMSG_DATA(m->hdr);
321         r = rtnl_message_parse(m,
322                                &m->rta_offset_tb,
323                                &m->rta_tb_size,
324                                IFLA_MAX,
325                                IFLA_RTA(ifi),
326                                IFLA_PAYLOAD(m->hdr));
327         if(r < 0)
328                 return;
329
330         assert_se(sd_rtnl_message_read_u32(m, IFLA_LINKINFO, &u32_data) == 0);
331
332         assert_se(sd_rtnl_message_exit_container(m) == -EINVAL);
333 }
334
335 static void test_match(void) {
336         _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
337
338         assert_se(sd_rtnl_open(&rtnl, 0) >= 0);
339
340         assert_se(sd_rtnl_add_match(rtnl, RTM_NEWLINK, &link_handler, NULL) >= 0);
341         assert_se(sd_rtnl_add_match(rtnl, RTM_NEWLINK, &link_handler, NULL) >= 0);
342
343         assert_se(sd_rtnl_remove_match(rtnl, RTM_NEWLINK, &link_handler, NULL) == 1);
344         assert_se(sd_rtnl_remove_match(rtnl, RTM_NEWLINK, &link_handler, NULL) == 1);
345         assert_se(sd_rtnl_remove_match(rtnl, RTM_NEWLINK, &link_handler, NULL) == 0);
346
347         assert_se((rtnl = sd_rtnl_unref(rtnl)) == NULL);
348 }
349
350 int main(void) {
351         sd_rtnl *rtnl;
352         sd_rtnl_message *m;
353         sd_rtnl_message *r;
354         char *string_data;
355         int if_loopback;
356         uint16_t type;
357
358         test_match();
359
360         test_multiple();
361
362         test_route();
363
364         test_container();
365
366         assert_se(sd_rtnl_open(&rtnl, 0) >= 0);
367         assert_se(rtnl);
368
369         if_loopback = (int) if_nametoindex("lo");
370         assert_se(if_loopback > 0);
371
372         test_async(if_loopback);
373
374         test_pipe(if_loopback);
375
376         test_event_loop(if_loopback);
377
378         test_link_configure(rtnl, if_loopback);
379
380         assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_GETLINK, if_loopback) >= 0);
381         assert_se(m);
382
383         assert_se(sd_rtnl_message_get_type(m, &type) >= 0);
384         assert_se(type == RTM_GETLINK);
385
386         assert_se(sd_rtnl_message_read_string(m, IFLA_IFNAME, &string_data) == -EPERM);
387
388         assert_se(sd_rtnl_call(rtnl, m, 0, &r) == 1);
389         assert_se(sd_rtnl_message_get_type(r, &type) >= 0);
390         assert_se(type == RTM_NEWLINK);
391
392         assert_se((r = sd_rtnl_message_unref(r)) == NULL);
393
394         assert_se(sd_rtnl_call(rtnl, m, -1, &r) == -EPERM);
395         assert_se((m = sd_rtnl_message_unref(m)) == NULL);
396         assert_se((r = sd_rtnl_message_unref(r)) == NULL);
397
398         test_link_get(rtnl, if_loopback);
399         test_address_get(rtnl, if_loopback);
400
401         assert_se(sd_rtnl_flush(rtnl) >= 0);
402         assert_se((m = sd_rtnl_message_unref(m)) == NULL);
403         assert_se((r = sd_rtnl_message_unref(r)) == NULL);
404         assert_se((rtnl = sd_rtnl_unref(rtnl)) == NULL);
405
406         return EXIT_SUCCESS;
407 }