chiark / gitweb /
53efed561a7b975267dc0e63c464abdc2af13957
[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_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_new_link(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
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         uint16_t type;
68
69         assert(sd_rtnl_message_new_link(RTM_GETLINK, ifindex, &m) >= 0);
70         assert(m);
71
72         /* u8 test cases  */
73         assert(sd_rtnl_message_append_u8(m, IFLA_CARRIER, 0) >= 0);
74         assert(sd_rtnl_message_append_u8(m, IFLA_OPERSTATE, 0) >= 0);
75         assert(sd_rtnl_message_append_u8(m, IFLA_LINKMODE, 0) >= 0);
76
77         /* u32 test cases */
78         assert(sd_rtnl_message_append_u32(m, IFLA_MTU, mtu) >= 0);
79         assert(sd_rtnl_message_append_u32(m, IFLA_GROUP, 0) >= 0);
80         assert(sd_rtnl_message_append_u32(m, IFLA_TXQLEN, 0) >= 0);
81         assert(sd_rtnl_message_append_u32(m, IFLA_NUM_TX_QUEUES, 0) >= 0);
82         assert(sd_rtnl_message_append_u32(m, IFLA_NUM_RX_QUEUES, 0) >= 0);
83
84         assert(sd_rtnl_call(rtnl, m, -1, &r) == 1);
85
86         /* u8 read back */
87         assert(sd_rtnl_message_read(m, &type, &data) == 1);
88         assert(type == IFLA_CARRIER);
89
90         assert(sd_rtnl_message_read(m, &type, &data) == 1);
91         assert(type == IFLA_OPERSTATE);
92
93         assert(sd_rtnl_message_read(m, &type, &data) == 1);
94         assert(type == IFLA_LINKMODE);
95
96         /* u32 read back */
97         assert(sd_rtnl_message_read(m, &type, (void **) &mtu_reply) == 1);
98         assert(type == IFLA_MTU);
99         assert(*mtu_reply == mtu);
100
101         assert(sd_rtnl_message_read(m, &type, &data) == 1);
102         assert(type == IFLA_GROUP);
103
104         assert(sd_rtnl_message_read(m, &type, &data) == 1);
105         assert(type == IFLA_TXQLEN);
106
107         assert(sd_rtnl_message_read(m, &type, &data) == 1);
108         assert(type == IFLA_NUM_TX_QUEUES);
109
110         assert(sd_rtnl_message_read(m, &type, &data) == 1);
111         assert(type == IFLA_NUM_RX_QUEUES);
112
113         while (sd_rtnl_message_read(r, &type, &data) > 0) {
114                 switch (type) {
115 //                        case IFLA_MTU:
116 //                                assert(*(unsigned int *) data == 65536);
117 //                                break;
118 //                        case IFLA_QDISC:
119 //                                assert(streq((char *) data, "noqueue"));
120 //                                break;
121                         case IFLA_IFNAME:
122                                 assert(streq((char *) data, "lo"));
123                                 break;
124                 }
125         }
126
127         assert(sd_rtnl_flush(rtnl) >= 0);
128         assert((m = sd_rtnl_message_unref(m)) == NULL);
129
130 }
131
132 static void test_route(void) {
133         _cleanup_rtnl_message_unref_ sd_rtnl_message *req;
134         struct in_addr addr;
135         uint32_t index = 2;
136         uint16_t type;
137         void *data;
138         int r;
139
140         r = sd_rtnl_message_new_route(RTM_NEWROUTE, AF_INET, &req);
141         if (r < 0) {
142                 log_error("Could not create RTM_NEWROUTE message: %s", strerror(-r));
143                 return;
144         }
145
146         addr.s_addr = htonl(INADDR_LOOPBACK);
147
148         r = sd_rtnl_message_append_in_addr(req, RTA_GATEWAY, &addr);
149         if (r < 0) {
150                 log_error("Could not append RTA_GATEWAY attribute: %s", strerror(-r));
151                 return;
152         }
153
154         r = sd_rtnl_message_append_u32(req, RTA_OIF, index);
155         if (r < 0) {
156                 log_error("Could not append RTA_OIF attribute: %s", strerror(-r));
157                 return;
158         }
159
160         assert(rtnl_message_seal(NULL, req) >= 0);
161
162         assert(sd_rtnl_message_read(req, &type, &data) > 0);
163         assert(type == RTA_GATEWAY);
164         assert(((struct in_addr *)data)->s_addr == addr.s_addr);
165
166         assert(sd_rtnl_message_read(req, &type, &data) > 0);
167         assert(type == RTA_OIF);
168         assert(*(uint32_t *) data == index);
169 }
170
171 static void test_multiple(void) {
172         sd_rtnl *rtnl1, *rtnl2;
173
174         assert(sd_rtnl_open(0, &rtnl1) >= 0);
175         assert(sd_rtnl_open(0, &rtnl2) >= 0);
176
177         rtnl1 = sd_rtnl_unref(rtnl1);
178         rtnl2 = sd_rtnl_unref(rtnl2);
179 }
180
181 static int link_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
182         void *data;
183         uint16_t type;
184         char *ifname = userdata;
185
186         assert(rtnl);
187         assert(m);
188
189         log_info("got link info about %s", ifname);
190         free(ifname);
191
192         while (sd_rtnl_message_read(m, &type, &data) > 0) {
193                 switch (type) {
194 //                        case IFLA_MTU:
195 //                                assert(*(unsigned int *) data == 65536);
196 //                                break;
197 //                        case IFLA_QDISC:
198 //                                assert(streq((char *) data, "noqueue"));
199 //                                break;
200                         case IFLA_IFNAME:
201                                 assert(streq((char *) data, "lo"));
202                                 break;
203                 }
204         }
205
206         return 1;
207 }
208
209 static void test_event_loop(int ifindex) {
210         _cleanup_event_unref_ sd_event *event = NULL;
211         _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
212         _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
213         char *ifname;
214
215         ifname = strdup("lo2");
216         assert(ifname);
217
218         assert(sd_rtnl_open(0, &rtnl) >= 0);
219         assert(sd_rtnl_message_new_link(RTM_GETLINK, ifindex, &m) >= 0);
220
221         assert(sd_rtnl_call_async(rtnl, m, &link_handler, ifname, 0, NULL) >= 0);
222
223         assert(sd_event_default(&event) >= 0);
224
225         assert(sd_rtnl_attach_event(rtnl, event, 0) >= 0);
226
227         assert(sd_event_run(event, 0) >= 0);
228
229         assert(sd_rtnl_detach_event(rtnl) >= 0);
230 }
231
232 static int pipe_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
233         int *counter = userdata;
234
235         (*counter) --;
236
237         log_info("got reply, %d left in pipe", *counter);
238
239         return sd_rtnl_message_get_errno(m);
240 }
241
242 static void test_async(int ifindex) {
243         _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
244         _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL, *r = NULL;
245         uint32_t serial;
246         char *ifname;
247
248         ifname = strdup("lo");
249         assert(ifname);
250
251         assert(sd_rtnl_open(0, &rtnl) >= 0);
252
253         assert(sd_rtnl_message_new_link(RTM_GETLINK, ifindex, &m) >= 0);
254
255         assert(sd_rtnl_call_async(rtnl, m, &link_handler, ifname, 0, &serial) >= 0);
256
257         assert(sd_rtnl_wait(rtnl, 0) >= 0);
258         assert(sd_rtnl_process(rtnl, &r) >= 0);
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(sd_rtnl_open(0, &rtnl) >= 0);
267
268         assert(sd_rtnl_message_new_link(RTM_GETLINK, ifindex, &m1) >= 0);
269         assert(sd_rtnl_message_new_link(RTM_GETLINK, ifindex, &m2) >= 0);
270
271         counter ++;
272         assert(sd_rtnl_call_async(rtnl, m1, &pipe_handler, &counter, 0, NULL) >= 0);
273
274         counter ++;
275         assert(sd_rtnl_call_async(rtnl, m2, &pipe_handler, &counter, 0, NULL) >= 0);
276
277         while (counter > 0) {
278                 assert(sd_rtnl_wait(rtnl, 0) >= 0);
279                 assert(sd_rtnl_process(rtnl, NULL) >= 0);
280         }
281 }
282
283 static void test_container(void) {
284         _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
285         uint16_t type;
286         void *data;
287
288         assert(sd_rtnl_message_new_link(RTM_NEWLINK, 0, &m) >= 0);
289
290         assert(sd_rtnl_message_open_container(m, IFLA_LINKINFO) >= 0);
291         assert(sd_rtnl_message_open_container(m, IFLA_LINKINFO) == -ENOTSUP);
292         assert(sd_rtnl_message_append_string(m, IFLA_INFO_KIND, "kind") >= 0);
293         assert(sd_rtnl_message_open_container(m, IFLA_INFO_DATA) >= 0);
294         assert(sd_rtnl_message_open_container(m, IFLA_INFO_DATA) == -ENOTSUP);
295         assert(sd_rtnl_message_append_u16(m, IFLA_VLAN_ID, 100) >= 0);
296         assert(sd_rtnl_message_close_container(m) >= 0);
297         assert(sd_rtnl_message_append_string(m, IFLA_INFO_KIND, "kind") >= 0);
298         assert(sd_rtnl_message_close_container(m) >= 0);
299         assert(sd_rtnl_message_close_container(m) == -EINVAL);
300
301         assert(rtnl_message_seal(NULL, m) >= 0);
302
303         assert(sd_rtnl_message_read(m, &type, &data) >= 0);
304         assert(type == IFLA_LINKINFO);
305         assert(data == NULL);
306         assert(sd_rtnl_message_read(m, &type, &data) >= 0);
307         assert(type == IFLA_INFO_KIND);
308         assert(streq("kind", (char *)data));
309         assert(sd_rtnl_message_read(m, &type, &data) >= 0);
310         assert(type == IFLA_INFO_DATA);
311         assert(data == NULL);
312         assert(sd_rtnl_message_read(m, &type, &data) >= 0);
313         assert(type == IFLA_VLAN_ID);
314         assert(*(uint16_t *)data == 100);
315         assert(sd_rtnl_message_read(m, &type, &data) == 0);
316         assert(sd_rtnl_message_exit_container(m) >= 0);
317         assert(sd_rtnl_message_read(m, &type, &data) >= 0);
318         assert(type == IFLA_INFO_KIND);
319         assert(streq("kind", (char *)data));
320         assert(sd_rtnl_message_read(m, &type, &data) == 0);
321         assert(sd_rtnl_message_exit_container(m) >= 0);
322         assert(sd_rtnl_message_exit_container(m) == -EINVAL);
323 }
324
325 static void test_match(void) {
326         _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
327
328         assert(sd_rtnl_open(0, &rtnl) >= 0);
329
330         assert(sd_rtnl_add_match(rtnl, RTM_NEWLINK, &link_handler, NULL) >= 0);
331         assert(sd_rtnl_add_match(rtnl, RTM_NEWLINK, &link_handler, NULL) >= 0);
332
333         assert(sd_rtnl_remove_match(rtnl, RTM_NEWLINK, &link_handler, NULL) == 1);
334         assert(sd_rtnl_remove_match(rtnl, RTM_NEWLINK, &link_handler, NULL) == 1);
335         assert(sd_rtnl_remove_match(rtnl, RTM_NEWLINK, &link_handler, NULL) == 0);
336 }
337
338 int main(void) {
339         sd_rtnl *rtnl;
340         sd_rtnl_message *m;
341         sd_rtnl_message *r;
342         void *data;
343         int if_loopback;
344         uint16_t type;
345
346         test_match();
347
348         test_multiple();
349
350         test_route();
351
352         test_container();
353
354         assert(sd_rtnl_open(0, &rtnl) >= 0);
355         assert(rtnl);
356
357         if_loopback = (int) if_nametoindex("lo");
358         assert(if_loopback > 0);
359
360         test_async(if_loopback);
361
362         test_pipe(if_loopback);
363
364         test_event_loop(if_loopback);
365
366         test_link_configure(rtnl, if_loopback);
367
368         assert(sd_rtnl_message_new_link(RTM_GETLINK, if_loopback, &m) >= 0);
369         assert(m);
370
371         assert(sd_rtnl_message_get_type(m, &type) >= 0);
372         assert(type == RTM_GETLINK);
373
374         assert(sd_rtnl_message_read(m, &type, &data) == -EPERM);
375
376         assert(sd_rtnl_call(rtnl, m, 0, &r) == 1);
377         assert(sd_rtnl_message_get_type(r, &type) >= 0);
378         assert(type == RTM_NEWLINK);
379
380         assert(sd_rtnl_message_read(m, &type, &data) == 0);
381         assert((r = sd_rtnl_message_unref(r)) == NULL);
382
383         assert(sd_rtnl_call(rtnl, m, -1, &r) == -EPERM);
384         assert((m = sd_rtnl_message_unref(m)) == NULL);
385         assert((r = sd_rtnl_message_unref(r)) == NULL);
386
387         test_link_get(rtnl, if_loopback);
388
389         assert(sd_rtnl_flush(rtnl) >= 0);
390         assert((m = sd_rtnl_message_unref(m)) == NULL);
391         assert((r = sd_rtnl_message_unref(r)) == NULL);
392         assert((rtnl = sd_rtnl_unref(rtnl)) == NULL);
393
394         return EXIT_SUCCESS;
395 }