chiark / gitweb /
sd-rtnl:introduce table-based lookup and typesafe read() functions
[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         uint16_t type;
36         const char *mac = "98:fe:94:3f:c6:18", *name = "test";
37         unsigned int mtu = 1450;
38         void *data;
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
48         assert_se(sd_rtnl_message_read(message, &type, &data) > 0);
49         assert_se(type == IFLA_IFNAME);
50         assert_se(streq(name, (char *) data));
51
52         assert_se(sd_rtnl_message_read(message, &type, &data) > 0);
53         assert_se(type == IFLA_ADDRESS);
54         assert_se(streq(mac, ether_ntoa(data)));
55
56         assert_se(sd_rtnl_message_read(message, &type, &data) > 0);
57         assert_se(type == IFLA_MTU);
58         assert_se(mtu == *(unsigned int *) data);
59 }
60
61 static void test_link_get(sd_rtnl *rtnl, int ifindex) {
62         sd_rtnl_message *m;
63         sd_rtnl_message *r;
64         unsigned int mtu = 1500;
65         unsigned int *mtu_reply;
66         void *data;
67         char *str_data;
68         uint16_t type;
69         uint8_t u8_data;
70         uint32_t u32_data;
71
72         assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_GETLINK, ifindex) >= 0);
73         assert_se(m);
74
75         /* u8 test cases  */
76         assert_se(sd_rtnl_message_append_u8(m, IFLA_CARRIER, 0) >= 0);
77         assert_se(sd_rtnl_message_append_u8(m, IFLA_OPERSTATE, 0) >= 0);
78         assert_se(sd_rtnl_message_append_u8(m, IFLA_LINKMODE, 0) >= 0);
79
80         /* u32 test cases */
81         assert_se(sd_rtnl_message_append_u32(m, IFLA_MTU, mtu) >= 0);
82         assert_se(sd_rtnl_message_append_u32(m, IFLA_GROUP, 0) >= 0);
83         assert_se(sd_rtnl_message_append_u32(m, IFLA_TXQLEN, 0) >= 0);
84         assert_se(sd_rtnl_message_append_u32(m, IFLA_NUM_TX_QUEUES, 0) >= 0);
85         assert_se(sd_rtnl_message_append_u32(m, IFLA_NUM_RX_QUEUES, 0) >= 0);
86
87         assert_se(sd_rtnl_call(rtnl, m, -1, &r) == 1);
88
89         /* u8 read back */
90         assert_se(sd_rtnl_message_read(m, &type, &data) == 1);
91         assert_se(type == IFLA_CARRIER);
92
93         assert_se(sd_rtnl_message_read(m, &type, &data) == 1);
94         assert_se(type == IFLA_OPERSTATE);
95
96         assert_se(sd_rtnl_message_read(m, &type, &data) == 1);
97         assert_se(type == IFLA_LINKMODE);
98
99         /* u32 read back */
100         assert_se(sd_rtnl_message_read(m, &type, (void **) &mtu_reply) == 1);
101         assert_se(type == IFLA_MTU);
102         assert_se(*mtu_reply == mtu);
103
104         assert_se(sd_rtnl_message_read(m, &type, &data) == 1);
105         assert_se(type == IFLA_GROUP);
106
107         assert_se(sd_rtnl_message_read(m, &type, &data) == 1);
108         assert_se(type == IFLA_TXQLEN);
109
110         assert_se(sd_rtnl_message_read(m, &type, &data) == 1);
111         assert_se(type == IFLA_NUM_TX_QUEUES);
112
113         assert_se(sd_rtnl_message_read(m, &type, &data) == 1);
114         assert_se(type == IFLA_NUM_RX_QUEUES);
115
116         while (sd_rtnl_message_read(r, &type, &data) > 0) {
117                 switch (type) {
118 //                        case IFLA_MTU:
119 //                                assert_se(*(unsigned int *) data == 65536);
120 //                                break;
121 //                        case IFLA_QDISC:
122 //                                assert_se(streq((char *) data, "noqueue"));
123 //                                break;
124                         case IFLA_IFNAME:
125                                 assert_se(streq((char *) data, "lo"));
126                                 break;
127                 }
128         }
129
130         assert_se(sd_rtnl_message_read_string(r, IFLA_IFNAME, &str_data) == 0);
131
132         assert_se(sd_rtnl_message_read_u8(r, IFLA_CARRIER, &u8_data) == 0);
133         assert_se(sd_rtnl_message_read_u8(r, IFLA_OPERSTATE, &u8_data) == 0);
134         assert_se(sd_rtnl_message_read_u8(r, IFLA_LINKMODE, &u8_data) == 0);
135
136         assert_se(sd_rtnl_message_read_u32(r, IFLA_MTU, &u32_data) == 0);
137         assert_se(sd_rtnl_message_read_u32(r, IFLA_GROUP, &u32_data) == 0);
138         assert_se(sd_rtnl_message_read_u32(r, IFLA_TXQLEN, &u32_data) == 0);
139         assert_se(sd_rtnl_message_read_u32(r, IFLA_NUM_TX_QUEUES, &u32_data) == 0);
140         assert_se(sd_rtnl_message_read_u32(r, IFLA_NUM_RX_QUEUES, &u32_data) == 0);
141
142         assert_se(sd_rtnl_flush(rtnl) >= 0);
143         assert_se((m = sd_rtnl_message_unref(m)) == NULL);
144         assert_se((r = sd_rtnl_message_unref(r)) == NULL);
145 }
146
147 static void test_route(void) {
148         _cleanup_rtnl_message_unref_ sd_rtnl_message *req;
149         struct in_addr addr;
150         uint32_t index = 2;
151         uint16_t type;
152         void *data;
153         uint32_t u32_data;
154         int r;
155         struct rtmsg *rtm;
156
157         r = sd_rtnl_message_new_route(NULL, &req, RTM_NEWROUTE, AF_INET);
158         if (r < 0) {
159                 log_error("Could not create RTM_NEWROUTE message: %s", strerror(-r));
160                 return;
161         }
162
163         addr.s_addr = htonl(INADDR_LOOPBACK);
164
165         r = sd_rtnl_message_append_in_addr(req, RTA_GATEWAY, &addr);
166         if (r < 0) {
167                 log_error("Could not append RTA_GATEWAY attribute: %s", strerror(-r));
168                 return;
169         }
170
171         r = sd_rtnl_message_append_u32(req, RTA_OIF, index);
172         if (r < 0) {
173                 log_error("Could not append RTA_OIF attribute: %s", strerror(-r));
174                 return;
175         }
176
177         assert_se(rtnl_message_seal(NULL, req) >= 0);
178
179         assert_se(sd_rtnl_message_read(req, &type, &data) > 0);
180         assert_se(type == RTA_GATEWAY);
181         assert_se(((struct in_addr *)data)->s_addr == addr.s_addr);
182
183         assert_se(sd_rtnl_message_read(req, &type, &data) > 0);
184         assert_se(type == RTA_OIF);
185         assert_se(*(uint32_t *) data == index);
186
187         rtm = NLMSG_DATA(req->hdr);
188         r = rtnl_message_parse(req,
189                                &req->rta_offset_tb,
190                                &req->rta_tb_size,
191                                RTA_MAX,
192                                RTM_RTA(rtm),
193                                RTM_PAYLOAD(req->hdr));
194
195         assert_se(sd_rtnl_message_read_u32(req, RTA_GATEWAY, &u32_data) == 0);
196         assert_se(sd_rtnl_message_read_u32(req, RTA_OIF, &u32_data) == 0);
197
198         assert_se((req = sd_rtnl_message_unref(req)) == NULL);
199 }
200
201 static void test_multiple(void) {
202         sd_rtnl *rtnl1, *rtnl2;
203
204         assert_se(sd_rtnl_open(&rtnl1, 0) >= 0);
205         assert_se(sd_rtnl_open(&rtnl2, 0) >= 0);
206
207         rtnl1 = sd_rtnl_unref(rtnl1);
208         rtnl2 = sd_rtnl_unref(rtnl2);
209 }
210
211 static int link_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
212         void *data;
213         uint16_t type;
214         char *ifname = userdata;
215
216         assert_se(rtnl);
217         assert_se(m);
218
219         log_info("got link info about %s", ifname);
220         free(ifname);
221
222         while (sd_rtnl_message_read(m, &type, &data) > 0) {
223                 switch (type) {
224 //                        case IFLA_MTU:
225 //                                assert_se(*(unsigned int *) data == 65536);
226 //                                break;
227 //                        case IFLA_QDISC:
228 //                                assert_se(streq((char *) data, "noqueue"));
229 //                                break;
230                         case IFLA_IFNAME:
231                                 assert_se(streq((char *) data, "lo"));
232                                 break;
233                 }
234         }
235
236         return 1;
237 }
238
239 static void test_event_loop(int ifindex) {
240         _cleanup_event_unref_ sd_event *event = NULL;
241         _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
242         _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
243         char *ifname;
244
245         ifname = strdup("lo2");
246         assert_se(ifname);
247
248         assert_se(sd_rtnl_open(&rtnl, 0) >= 0);
249         assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_GETLINK, ifindex) >= 0);
250
251         assert_se(sd_rtnl_call_async(rtnl, m, &link_handler, ifname, 0, NULL) >= 0);
252
253         assert_se(sd_event_default(&event) >= 0);
254
255         assert_se(sd_rtnl_attach_event(rtnl, event, 0) >= 0);
256
257         assert_se(sd_event_run(event, 0) >= 0);
258
259         assert_se(sd_rtnl_detach_event(rtnl) >= 0);
260
261         assert_se((rtnl = sd_rtnl_unref(rtnl)) == NULL);
262 }
263
264 static int pipe_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
265         int *counter = userdata;
266
267         (*counter) --;
268
269         log_info("got reply, %d left in pipe", *counter);
270
271         return sd_rtnl_message_get_errno(m);
272 }
273
274 static void test_async(int ifindex) {
275         _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
276         _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL, *r = NULL;
277         uint32_t serial;
278         char *ifname;
279
280         ifname = strdup("lo");
281         assert_se(ifname);
282
283         assert_se(sd_rtnl_open(&rtnl, 0) >= 0);
284
285         assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_GETLINK, ifindex) >= 0);
286
287         assert_se(sd_rtnl_call_async(rtnl, m, &link_handler, ifname, 0, &serial) >= 0);
288
289         assert_se(sd_rtnl_wait(rtnl, 0) >= 0);
290         assert_se(sd_rtnl_process(rtnl, &r) >= 0);
291
292         assert_se((rtnl = sd_rtnl_unref(rtnl)) == NULL);
293 }
294
295 static void test_pipe(int ifindex) {
296         _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
297         _cleanup_rtnl_message_unref_ sd_rtnl_message *m1 = NULL, *m2 = NULL;
298         int counter = 0;
299
300         assert_se(sd_rtnl_open(&rtnl, 0) >= 0);
301
302         assert_se(sd_rtnl_message_new_link(rtnl, &m1, RTM_GETLINK, ifindex) >= 0);
303         assert_se(sd_rtnl_message_new_link(rtnl, &m2, RTM_GETLINK, ifindex) >= 0);
304
305         counter ++;
306         assert_se(sd_rtnl_call_async(rtnl, m1, &pipe_handler, &counter, 0, NULL) >= 0);
307
308         counter ++;
309         assert_se(sd_rtnl_call_async(rtnl, m2, &pipe_handler, &counter, 0, NULL) >= 0);
310
311         while (counter > 0) {
312                 assert_se(sd_rtnl_wait(rtnl, 0) >= 0);
313                 assert_se(sd_rtnl_process(rtnl, NULL) >= 0);
314         }
315
316         assert_se((rtnl = sd_rtnl_unref(rtnl)) == NULL);
317 }
318
319 static void test_container(void) {
320         _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
321         uint16_t type;
322         uint32_t u32_data;
323         void *data;
324         int r;
325         struct ifinfomsg *ifi;
326
327         assert_se(sd_rtnl_message_new_link(NULL, &m, RTM_NEWLINK, 0) >= 0);
328
329         assert_se(sd_rtnl_message_open_container(m, IFLA_LINKINFO) >= 0);
330         assert_se(sd_rtnl_message_open_container(m, IFLA_LINKINFO) == -ENOTSUP);
331         assert_se(sd_rtnl_message_append_string(m, IFLA_INFO_KIND, "kind") >= 0);
332         assert_se(sd_rtnl_message_open_container(m, IFLA_INFO_DATA) >= 0);
333         assert_se(sd_rtnl_message_open_container(m, IFLA_INFO_DATA) == -ENOTSUP);
334         assert_se(sd_rtnl_message_append_u16(m, IFLA_VLAN_ID, 100) >= 0);
335         assert_se(sd_rtnl_message_close_container(m) >= 0);
336         assert_se(sd_rtnl_message_append_string(m, IFLA_INFO_KIND, "kind") >= 0);
337         assert_se(sd_rtnl_message_close_container(m) >= 0);
338         assert_se(sd_rtnl_message_close_container(m) == -EINVAL);
339
340         assert_se(rtnl_message_seal(NULL, m) >= 0);
341
342         assert_se(sd_rtnl_message_read(m, &type, &data) >= 0);
343         assert_se(type == IFLA_LINKINFO);
344         assert_se(data == NULL);
345 /*
346         assert_se(sd_rtnl_message_read(m, &type, &data) >= 0);
347         assert_se(type == IFLA_INFO_KIND);
348         assert_se(streq("kind", (char *)data));
349         assert_se(sd_rtnl_message_read(m, &type, &data) >= 0);
350         assert_se(type == IFLA_INFO_DATA);
351         assert_se(data == NULL);
352         assert_se(sd_rtnl_message_read(m, &type, &data) >= 0);
353         assert_se(type == IFLA_VLAN_ID);
354         assert_se(*(uint16_t *)data == 100);
355         assert_se(sd_rtnl_message_read(m, &type, &data) == 0);
356         assert_se(sd_rtnl_message_exit_container(m) >= 0);
357         assert_se(sd_rtnl_message_read(m, &type, &data) >= 0);
358         assert_se(type == IFLA_INFO_KIND);
359         assert_se(streq("kind", (char *)data));
360         assert_se(sd_rtnl_message_read(m, &type, &data) == 0);
361         assert_se(sd_rtnl_message_exit_container(m) >= 0);
362 */
363
364         ifi = NLMSG_DATA(m->hdr);
365         r = rtnl_message_parse(m,
366                                &m->rta_offset_tb,
367                                &m->rta_tb_size,
368                                IFLA_MAX,
369                                IFLA_RTA(ifi),
370                                IFLA_PAYLOAD(m->hdr));
371         if(r < 0)
372                 return;
373
374         assert_se(sd_rtnl_message_read_u32(m, IFLA_LINKINFO, &u32_data) == 0);
375
376         assert_se(sd_rtnl_message_exit_container(m) == -EINVAL);
377 }
378
379 static void test_match(void) {
380         _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
381
382         assert_se(sd_rtnl_open(&rtnl, 0) >= 0);
383
384         assert_se(sd_rtnl_add_match(rtnl, RTM_NEWLINK, &link_handler, NULL) >= 0);
385         assert_se(sd_rtnl_add_match(rtnl, RTM_NEWLINK, &link_handler, NULL) >= 0);
386
387         assert_se(sd_rtnl_remove_match(rtnl, RTM_NEWLINK, &link_handler, NULL) == 1);
388         assert_se(sd_rtnl_remove_match(rtnl, RTM_NEWLINK, &link_handler, NULL) == 1);
389         assert_se(sd_rtnl_remove_match(rtnl, RTM_NEWLINK, &link_handler, NULL) == 0);
390
391         assert_se((rtnl = sd_rtnl_unref(rtnl)) == NULL);
392 }
393
394 int main(void) {
395         sd_rtnl *rtnl;
396         sd_rtnl_message *m;
397         sd_rtnl_message *r;
398         void *data;
399         int if_loopback;
400         uint16_t type;
401
402         test_match();
403
404         test_multiple();
405
406         test_route();
407
408         test_container();
409
410         assert_se(sd_rtnl_open(&rtnl, 0) >= 0);
411         assert_se(rtnl);
412
413         if_loopback = (int) if_nametoindex("lo");
414         assert_se(if_loopback > 0);
415
416         test_async(if_loopback);
417
418         test_pipe(if_loopback);
419
420         test_event_loop(if_loopback);
421
422         test_link_configure(rtnl, if_loopback);
423
424         assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_GETLINK, if_loopback) >= 0);
425         assert_se(m);
426
427         assert_se(sd_rtnl_message_get_type(m, &type) >= 0);
428         assert_se(type == RTM_GETLINK);
429
430         assert_se(sd_rtnl_message_read(m, &type, &data) == -EPERM);
431
432         assert_se(sd_rtnl_call(rtnl, m, 0, &r) == 1);
433         assert_se(sd_rtnl_message_get_type(r, &type) >= 0);
434         assert_se(type == RTM_NEWLINK);
435
436         assert_se(sd_rtnl_message_read(m, &type, &data) == 0);
437         assert_se((r = sd_rtnl_message_unref(r)) == NULL);
438
439         assert_se(sd_rtnl_call(rtnl, m, -1, &r) == -EPERM);
440         assert_se((m = sd_rtnl_message_unref(m)) == NULL);
441         assert_se((r = sd_rtnl_message_unref(r)) == NULL);
442
443         test_link_get(rtnl, if_loopback);
444
445         assert_se(sd_rtnl_flush(rtnl) >= 0);
446         assert_se((m = sd_rtnl_message_unref(m)) == NULL);
447         assert_se((r = sd_rtnl_message_unref(r)) == NULL);
448         assert_se((rtnl = sd_rtnl_unref(rtnl)) == NULL);
449
450         return EXIT_SUCCESS;
451 }