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