chiark / gitweb /
rtnl: add callback support
[elogind.git] / src / libsystemd-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 "event-util.h"
31
32 static void test_link_configure(sd_rtnl *rtnl, int ifindex) {
33         _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *message;
34         uint16_t type;
35         const char *mac = "98:fe:94:3f:c6:18", *name = "test";
36         unsigned int mtu = 1450;
37         void *data;
38
39         /* we'd really like to test NEWLINK, but let's not mess with the running kernel */
40         assert(sd_rtnl_message_link_new(RTM_GETLINK, ifindex, 0, 0, &message) >= 0);
41         assert(sd_rtnl_message_append(message, IFLA_IFNAME, name) >= 0);
42         assert(sd_rtnl_message_append(message, IFLA_ADDRESS, ether_aton(mac)) >= 0);
43         assert(sd_rtnl_message_append(message, IFLA_MTU, &mtu) >= 0);
44
45         assert(sd_rtnl_message_read(message, &type, &data) >= 0);
46         assert(type == IFLA_IFNAME);
47         assert(streq(name, (char *) data));
48
49         assert(sd_rtnl_message_read(message, &type, &data) >= 0);
50         assert(type == IFLA_ADDRESS);
51         assert(streq(mac, ether_ntoa(data)));
52
53         assert(sd_rtnl_message_read(message, &type, &data) >= 0);
54         assert(type == IFLA_MTU);
55         assert(mtu == *(unsigned int *) data);
56
57         assert(sd_rtnl_call(rtnl, message, 0, NULL) == 1);
58 }
59
60 static void test_route(void) {
61         _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *req;
62         uint32_t addr = htonl(INADDR_LOOPBACK);
63         uint32_t index = 2;
64         uint16_t type;
65         void *data;
66         int r;
67
68         r = sd_rtnl_message_route_new(RTM_NEWROUTE, AF_INET, 0, 0, 0,
69                                       RT_TABLE_MAIN, RT_SCOPE_UNIVERSE, RTPROT_BOOT,
70                                       RTN_UNICAST, 0, &req);
71         if (r < 0) {
72                 log_error("Could not create RTM_NEWROUTE message: %s", strerror(-r));
73                 return;
74         }
75
76         r = sd_rtnl_message_append(req, RTA_GATEWAY, &addr);
77         if (r < 0) {
78                 log_error("Could not append RTA_GATEWAY attribute: %s", strerror(-r));
79                 return;
80         }
81
82         r = sd_rtnl_message_append(req, RTA_OIF, &index);
83         if (r < 0) {
84                 log_error("Could not append RTA_OIF attribute: %s", strerror(-r));
85                 return;
86         }
87
88         assert(sd_rtnl_message_read(req, &type, &data) > 0);
89         assert(type == RTA_GATEWAY);
90         assert(*(uint32_t *) data == addr);
91
92         assert(sd_rtnl_message_read(req, &type, &data) > 0);
93         assert(type == RTA_OIF);
94         assert(*(uint32_t *) data == index);
95 }
96
97 static void test_multiple(void) {
98         sd_rtnl *rtnl1, *rtnl2;
99
100         assert(sd_rtnl_open(0, &rtnl1) >= 0);
101         assert(sd_rtnl_open(0, &rtnl2) >= 0);
102
103         rtnl1 = sd_rtnl_unref(rtnl1);
104         rtnl2 = sd_rtnl_unref(rtnl2);
105 }
106
107 static int link_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
108         void *data;
109         uint16_t type;
110         char *ifname = userdata;
111
112         assert(rtnl);
113         assert(m);
114
115         log_info("got link info about %s", ifname);
116         free(ifname);
117
118         while (sd_rtnl_message_read(m, &type, &data) > 0) {
119                 switch (type) {
120 //                        case IFLA_MTU:
121 //                                assert(*(unsigned int *) data == 65536);
122 //                                break;
123 //                        case IFLA_QDISC:
124 //                                assert(streq((char *) data, "noqueue"));
125 //                                break;
126                         case IFLA_IFNAME:
127                                 assert(streq((char *) data, "lo"));
128                                 break;
129                 }
130         }
131
132         return 1;
133 }
134
135 static void test_event_loop(int ifindex) {
136         _cleanup_event_unref_ sd_event *event = NULL;
137         _cleanup_sd_rtnl_unref_ sd_rtnl *rtnl = NULL;
138         _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *m = NULL;
139         char *ifname;
140
141         ifname = strdup("lo2");
142         assert(ifname);
143
144         assert(sd_rtnl_open(0, &rtnl) >= 0);
145         assert(sd_rtnl_message_link_new(RTM_GETLINK, ifindex, 0, 0, &m) >= 0);
146
147         assert(sd_rtnl_call_async(rtnl, m, &link_handler, ifname, 0, NULL) >= 0);
148
149         assert(sd_event_default(&event) >= 0);
150
151         assert(sd_rtnl_attach_event(rtnl, event, 0) >= 0);
152
153         assert(sd_event_run(event, 0) >= 0);
154
155         assert(sd_rtnl_detach_event(rtnl) >= 0);
156 }
157
158 static int pipe_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
159         int *counter = userdata;
160
161         (*counter) --;
162
163         log_info("got reply, %d left in pipe", *counter);
164
165         return sd_rtnl_message_get_errno(m);
166 }
167
168 static void test_async(int ifindex) {
169         _cleanup_sd_rtnl_unref_ sd_rtnl *rtnl = NULL;
170         _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *m = NULL, *r = NULL;
171         uint32_t serial;
172         char *ifname;
173
174         ifname = strdup("lo");
175         assert(ifname);
176
177         assert(sd_rtnl_open(0, &rtnl) >= 0);
178
179         assert(sd_rtnl_message_link_new(RTM_GETLINK, ifindex, 0, 0, &m) >= 0);
180
181         assert(sd_rtnl_call_async(rtnl, m, &link_handler, ifname, 0, &serial) >= 0);
182
183         assert(sd_rtnl_wait(rtnl, 0) >= 0);
184         assert(sd_rtnl_process(rtnl, &r) >= 0);
185 }
186
187 static void test_pipe(int ifindex) {
188         _cleanup_sd_rtnl_unref_ sd_rtnl *rtnl = NULL;
189         _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *m1 = NULL, *m2 = NULL;
190         int counter = 0;
191
192         assert(sd_rtnl_open(0, &rtnl) >= 0);
193
194         assert(sd_rtnl_message_link_new(RTM_GETLINK, ifindex, 0, 0, &m1) >= 0);
195         assert(sd_rtnl_message_link_new(RTM_GETLINK, ifindex, 0, 0, &m2) >= 0);
196
197         counter ++;
198         assert(sd_rtnl_call_async(rtnl, m1, &pipe_handler, &counter, 0, NULL) >= 0);
199
200         counter ++;
201         assert(sd_rtnl_call_async(rtnl, m2, &pipe_handler, &counter, 0, NULL) >= 0);
202
203         while (counter > 0) {
204                 assert(sd_rtnl_wait(rtnl, 0) >= 0);
205                 assert(sd_rtnl_process(rtnl, NULL) >= 0);
206         }
207 }
208
209 static void test_container(void) {
210         _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *m = NULL;
211         uint16_t type;
212         void *data;
213
214         assert(sd_rtnl_message_link_new(RTM_NEWLINK, 0, 0, 0, &m) >= 0);
215
216         assert(sd_rtnl_message_open_container(m, IFLA_LINKINFO) >= 0);
217         assert(sd_rtnl_message_open_container(m, IFLA_LINKINFO) == -EINVAL);
218         assert(sd_rtnl_message_append(m, IFLA_INFO_KIND, "kind") >= 0);
219         assert(sd_rtnl_message_close_container(m) >= 0);
220         assert(sd_rtnl_message_close_container(m) == -EINVAL);
221
222         assert(sd_rtnl_message_read(m, &type, &data) == -EINVAL);
223
224 /* TODO: add support for entering containers
225         assert(sd_rtnl_message_read(m, &type, &data) > 0);
226         assert(type == IFLA_INFO_KIND);
227         assert(streq("kind", (char *) data));
228
229         assert(sd_rtnl_message_read(m, &type, &data) == 0);
230 */
231 }
232
233 static void test_match(void) {
234         _cleanup_sd_rtnl_unref_ sd_rtnl *rtnl = NULL;
235
236         assert(sd_rtnl_open(0, &rtnl) >= 0);
237
238         assert(sd_rtnl_add_match(rtnl, 0, &link_handler, NULL) == -EINVAL);
239
240         assert(sd_rtnl_add_match(rtnl, RTMGRP_LINK, &link_handler, NULL) >= 0);
241         assert(sd_rtnl_add_match(rtnl, RTMGRP_LINK, &link_handler, NULL) >= 0);
242
243         assert(sd_rtnl_remove_match(rtnl, RTMGRP_LINK, &link_handler, NULL) == 1);
244         assert(sd_rtnl_remove_match(rtnl, RTMGRP_LINK, &link_handler, NULL) == 1);
245         assert(sd_rtnl_remove_match(rtnl, RTMGRP_LINK, &link_handler, NULL) == 0);
246 }
247
248 int main(void) {
249         sd_rtnl *rtnl;
250         sd_rtnl_message *m;
251         sd_rtnl_message *r;
252         void *data;
253         int if_loopback;
254         uint16_t type;
255         unsigned int mtu = 0;
256         unsigned int *mtu_reply;
257
258         test_match();
259
260         test_multiple();
261
262         test_route();
263
264         test_container();
265
266         assert(sd_rtnl_open(0, &rtnl) >= 0);
267         assert(rtnl);
268
269         if_loopback = (int) if_nametoindex("lo");
270         assert(if_loopback > 0);
271
272         test_async(if_loopback);
273
274         test_pipe(if_loopback);
275
276         test_event_loop(if_loopback);
277
278         test_link_configure(rtnl, if_loopback);
279
280         assert(sd_rtnl_message_link_new(RTM_GETLINK, if_loopback, 0, 0, &m) >= 0);
281         assert(m);
282
283         assert(sd_rtnl_message_get_type(m, &type) >= 0);
284         assert(type == RTM_GETLINK);
285
286         assert(sd_rtnl_message_read(m, &type, &data) == 0);
287
288         assert(sd_rtnl_call(rtnl, m, 0, &r) == 1);
289         assert(sd_rtnl_message_get_type(r, &type) >= 0);
290         assert(type == RTM_NEWLINK);
291
292         assert(sd_rtnl_message_read(m, &type, &data) == 0);
293         assert((r = sd_rtnl_message_unref(r)) == NULL);
294
295         assert(sd_rtnl_call(rtnl, m, -1, &r) == -EPERM);
296         assert((m = sd_rtnl_message_unref(m)) == NULL);
297         assert((r = sd_rtnl_message_unref(r)) == NULL);
298
299         assert(sd_rtnl_message_link_new(RTM_GETLINK, if_loopback, 0, 0, &m) >= 0);
300         assert(m);
301
302         assert(sd_rtnl_message_append(m, IFLA_MTU, &mtu) >= 0);
303         assert(sd_rtnl_message_read(m, &type, (void **) &mtu_reply) == 1);
304
305         assert(type == IFLA_MTU);
306         assert(*mtu_reply == 0);
307
308         assert(sd_rtnl_message_read(m, &type, &data) == 0);
309
310         assert(sd_rtnl_call(rtnl, m, -1, &r) == 1);
311         while (sd_rtnl_message_read(r, &type, &data) > 0) {
312                 switch (type) {
313 //                        case IFLA_MTU:
314 //                                assert(*(unsigned int *) data == 65536);
315 //                                break;
316 //                        case IFLA_QDISC:
317 //                                assert(streq((char *) data, "noqueue"));
318 //                                break;
319                         case IFLA_IFNAME:
320                                 assert(streq((char *) data, "lo"));
321                                 break;
322                 }
323         }
324
325         assert(sd_rtnl_flush(rtnl) >= 0);
326
327         assert((m = sd_rtnl_message_unref(m)) == NULL);
328         assert((r = sd_rtnl_message_unref(r)) == NULL);
329         assert((rtnl = sd_rtnl_unref(rtnl)) == NULL);
330
331         return EXIT_SUCCESS;
332 }