chiark / gitweb /
sd-rtnl: add support for reading containers
[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 <linux/rtnetlink.h>
23 #include <netinet/ether.h>
24
25 #include "util.h"
26 #include "macro.h"
27 #include "sd-rtnl.h"
28 #include "socket-util.h"
29 #include "rtnl-util.h"
30 #include "rtnl-internal.h"
31 #include "event-util.h"
32
33 static void test_link_configure(sd_rtnl *rtnl, int ifindex) {
34         _cleanup_sd_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(sd_rtnl_message_link_new(RTM_GETLINK, ifindex, &message) >= 0);
42         assert(sd_rtnl_message_append_string(message, IFLA_IFNAME, name) >= 0);
43         assert(sd_rtnl_message_append_ether_addr(message, IFLA_ADDRESS, ether_aton(mac)) >= 0);
44         assert(sd_rtnl_message_append_u32(message, IFLA_MTU, mtu) >= 0);
45
46         assert(sd_rtnl_call(rtnl, message, 0, NULL) == 1);
47
48         assert(sd_rtnl_message_read(message, &type, &data) > 0);
49         assert(type == IFLA_IFNAME);
50         assert(streq(name, (char *) data));
51
52         assert(sd_rtnl_message_read(message, &type, &data) > 0);
53         assert(type == IFLA_ADDRESS);
54         assert(streq(mac, ether_ntoa(data)));
55
56         assert(sd_rtnl_message_read(message, &type, &data) > 0);
57         assert(type == IFLA_MTU);
58         assert(mtu == *(unsigned int *) data);
59 }
60
61 static void test_route(void) {
62         _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *req;
63         struct in_addr addr;
64         uint32_t index = 2;
65         uint16_t type;
66         void *data;
67         int r;
68
69         r = sd_rtnl_message_route_new(RTM_NEWROUTE, AF_INET, &req);
70         if (r < 0) {
71                 log_error("Could not create RTM_NEWROUTE message: %s", strerror(-r));
72                 return;
73         }
74
75         addr.s_addr = htonl(INADDR_LOOPBACK);
76
77         r = sd_rtnl_message_append_in_addr(req, RTA_GATEWAY, &addr);
78         if (r < 0) {
79                 log_error("Could not append RTA_GATEWAY attribute: %s", strerror(-r));
80                 return;
81         }
82
83         r = sd_rtnl_message_append_u32(req, RTA_OIF, index);
84         if (r < 0) {
85                 log_error("Could not append RTA_OIF attribute: %s", strerror(-r));
86                 return;
87         }
88
89         assert(message_seal(NULL, req) >= 0);
90
91         assert(sd_rtnl_message_read(req, &type, &data) > 0);
92         assert(type == RTA_GATEWAY);
93         assert(((struct in_addr *)data)->s_addr == addr.s_addr);
94
95         assert(sd_rtnl_message_read(req, &type, &data) > 0);
96         assert(type == RTA_OIF);
97         assert(*(uint32_t *) data == index);
98 }
99
100 static void test_multiple(void) {
101         sd_rtnl *rtnl1, *rtnl2;
102
103         assert(sd_rtnl_open(0, &rtnl1) >= 0);
104         assert(sd_rtnl_open(0, &rtnl2) >= 0);
105
106         rtnl1 = sd_rtnl_unref(rtnl1);
107         rtnl2 = sd_rtnl_unref(rtnl2);
108 }
109
110 static int link_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
111         void *data;
112         uint16_t type;
113         char *ifname = userdata;
114
115         assert(rtnl);
116         assert(m);
117
118         log_info("got link info about %s", ifname);
119         free(ifname);
120
121         while (sd_rtnl_message_read(m, &type, &data) > 0) {
122                 switch (type) {
123 //                        case IFLA_MTU:
124 //                                assert(*(unsigned int *) data == 65536);
125 //                                break;
126 //                        case IFLA_QDISC:
127 //                                assert(streq((char *) data, "noqueue"));
128 //                                break;
129                         case IFLA_IFNAME:
130                                 assert(streq((char *) data, "lo"));
131                                 break;
132                 }
133         }
134
135         return 1;
136 }
137
138 static void test_event_loop(int ifindex) {
139         _cleanup_event_unref_ sd_event *event = NULL;
140         _cleanup_sd_rtnl_unref_ sd_rtnl *rtnl = NULL;
141         _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *m = NULL;
142         char *ifname;
143
144         ifname = strdup("lo2");
145         assert(ifname);
146
147         assert(sd_rtnl_open(0, &rtnl) >= 0);
148         assert(sd_rtnl_message_link_new(RTM_GETLINK, ifindex, &m) >= 0);
149
150         assert(sd_rtnl_call_async(rtnl, m, &link_handler, ifname, 0, NULL) >= 0);
151
152         assert(sd_event_default(&event) >= 0);
153
154         assert(sd_rtnl_attach_event(rtnl, event, 0) >= 0);
155
156         assert(sd_event_run(event, 0) >= 0);
157
158         assert(sd_rtnl_detach_event(rtnl) >= 0);
159 }
160
161 static int pipe_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
162         int *counter = userdata;
163
164         (*counter) --;
165
166         log_info("got reply, %d left in pipe", *counter);
167
168         return sd_rtnl_message_get_errno(m);
169 }
170
171 static void test_async(int ifindex) {
172         _cleanup_sd_rtnl_unref_ sd_rtnl *rtnl = NULL;
173         _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *m = NULL, *r = NULL;
174         uint32_t serial;
175         char *ifname;
176
177         ifname = strdup("lo");
178         assert(ifname);
179
180         assert(sd_rtnl_open(0, &rtnl) >= 0);
181
182         assert(sd_rtnl_message_link_new(RTM_GETLINK, ifindex, &m) >= 0);
183
184         assert(sd_rtnl_call_async(rtnl, m, &link_handler, ifname, 0, &serial) >= 0);
185
186         assert(sd_rtnl_wait(rtnl, 0) >= 0);
187         assert(sd_rtnl_process(rtnl, &r) >= 0);
188 }
189
190 static void test_pipe(int ifindex) {
191         _cleanup_sd_rtnl_unref_ sd_rtnl *rtnl = NULL;
192         _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *m1 = NULL, *m2 = NULL;
193         int counter = 0;
194
195         assert(sd_rtnl_open(0, &rtnl) >= 0);
196
197         assert(sd_rtnl_message_link_new(RTM_GETLINK, ifindex, &m1) >= 0);
198         assert(sd_rtnl_message_link_new(RTM_GETLINK, ifindex, &m2) >= 0);
199
200         counter ++;
201         assert(sd_rtnl_call_async(rtnl, m1, &pipe_handler, &counter, 0, NULL) >= 0);
202
203         counter ++;
204         assert(sd_rtnl_call_async(rtnl, m2, &pipe_handler, &counter, 0, NULL) >= 0);
205
206         while (counter > 0) {
207                 assert(sd_rtnl_wait(rtnl, 0) >= 0);
208                 assert(sd_rtnl_process(rtnl, NULL) >= 0);
209         }
210 }
211
212 static void test_container(void) {
213         _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *m = NULL;
214         uint16_t type;
215         void *data;
216
217         assert(sd_rtnl_message_link_new(RTM_NEWLINK, 0, &m) >= 0);
218
219         assert(sd_rtnl_message_open_container(m, IFLA_LINKINFO) >= 0);
220         assert(sd_rtnl_message_open_container(m, IFLA_LINKINFO) == -ENOTSUP);
221         assert(sd_rtnl_message_append_string(m, IFLA_INFO_KIND, "kind") >= 0);
222         assert(sd_rtnl_message_open_container(m, IFLA_INFO_DATA) >= 0);
223         assert(sd_rtnl_message_open_container(m, IFLA_INFO_DATA) == -ENOTSUP);
224         assert(sd_rtnl_message_append_u16(m, IFLA_VLAN_ID, 100) >= 0);
225         assert(sd_rtnl_message_close_container(m) >= 0);
226         assert(sd_rtnl_message_append_string(m, IFLA_INFO_KIND, "kind") >= 0);
227         assert(sd_rtnl_message_close_container(m) >= 0);
228         assert(sd_rtnl_message_close_container(m) == -EINVAL);
229
230         assert(message_seal(NULL, m) >= 0);
231
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);
236         assert(type == IFLA_INFO_KIND);
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);
250 }
251
252 static void test_match(void) {
253         _cleanup_sd_rtnl_unref_ sd_rtnl *rtnl = NULL;
254
255         assert(sd_rtnl_open(0, &rtnl) >= 0);
256
257         assert(sd_rtnl_add_match(rtnl, RTM_NEWLINK, &link_handler, NULL) >= 0);
258         assert(sd_rtnl_add_match(rtnl, RTM_NEWLINK, &link_handler, NULL) >= 0);
259
260         assert(sd_rtnl_remove_match(rtnl, RTM_NEWLINK, &link_handler, NULL) == 1);
261         assert(sd_rtnl_remove_match(rtnl, RTM_NEWLINK, &link_handler, NULL) == 1);
262         assert(sd_rtnl_remove_match(rtnl, RTM_NEWLINK, &link_handler, NULL) == 0);
263 }
264
265 int main(void) {
266         sd_rtnl *rtnl;
267         sd_rtnl_message *m;
268         sd_rtnl_message *r;
269         void *data;
270         int if_loopback;
271         uint16_t type;
272         unsigned int mtu = 0;
273         unsigned int *mtu_reply;
274
275         test_match();
276
277         test_multiple();
278
279         test_route();
280
281         test_container();
282
283         assert(sd_rtnl_open(0, &rtnl) >= 0);
284         assert(rtnl);
285
286         if_loopback = (int) if_nametoindex("lo");
287         assert(if_loopback > 0);
288
289         test_async(if_loopback);
290
291         test_pipe(if_loopback);
292
293         test_event_loop(if_loopback);
294
295         test_link_configure(rtnl, if_loopback);
296
297         assert(sd_rtnl_message_link_new(RTM_GETLINK, if_loopback, &m) >= 0);
298         assert(m);
299
300         assert(sd_rtnl_message_get_type(m, &type) >= 0);
301         assert(type == RTM_GETLINK);
302
303         assert(sd_rtnl_message_read(m, &type, &data) == -EPERM);
304
305         assert(sd_rtnl_call(rtnl, m, 0, &r) == 1);
306         assert(sd_rtnl_message_get_type(r, &type) >= 0);
307         assert(type == RTM_NEWLINK);
308
309         assert(sd_rtnl_message_read(m, &type, &data) == 0);
310         assert((r = sd_rtnl_message_unref(r)) == NULL);
311
312         assert(sd_rtnl_call(rtnl, m, -1, &r) == -EPERM);
313         assert((m = sd_rtnl_message_unref(m)) == NULL);
314         assert((r = sd_rtnl_message_unref(r)) == NULL);
315
316         assert(sd_rtnl_message_link_new(RTM_GETLINK, if_loopback, &m) >= 0);
317         assert(m);
318
319         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);
322         assert(sd_rtnl_message_read(m, &type, (void **) &mtu_reply) == 1);
323
324         assert(type == IFLA_MTU);
325         assert(*mtu_reply == 0);
326
327         assert(sd_rtnl_message_read(m, &type, &data) == 0);
328
329         while (sd_rtnl_message_read(r, &type, &data) > 0) {
330                 switch (type) {
331 //                        case IFLA_MTU:
332 //                                assert(*(unsigned int *) data == 65536);
333 //                                break;
334 //                        case IFLA_QDISC:
335 //                                assert(streq((char *) data, "noqueue"));
336 //                                break;
337                         case IFLA_IFNAME:
338                                 assert(streq((char *) data, "lo"));
339                                 break;
340                 }
341         }
342
343         assert(sd_rtnl_flush(rtnl) >= 0);
344
345         assert((m = sd_rtnl_message_unref(m)) == NULL);
346         assert((r = sd_rtnl_message_unref(r)) == NULL);
347         assert((rtnl = sd_rtnl_unref(rtnl)) == NULL);
348
349         return EXIT_SUCCESS;
350 }