chiark / gitweb /
4b6e5339d9ec05807d87f21df460e997df2ad01a
[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 #include <net/if.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 #include "missing.h"
32 #include "rtnl-internal.h"
33
34 static void test_link_configure(sd_rtnl *rtnl, int ifindex) {
35         _cleanup_rtnl_message_unref_ sd_rtnl_message *message;
36         const char *mac = "98:fe:94:3f:c6:18", *name = "test";
37         unsigned int mtu = 1450, mtu_out;
38         const char *name_out;
39         struct ether_addr mac_out;
40
41         /* we'd really like to test NEWLINK, but let's not mess with the running kernel */
42         assert_se(sd_rtnl_message_new_link(rtnl, &message, RTM_GETLINK, ifindex) >= 0);
43         assert_se(sd_rtnl_message_append_string(message, IFLA_IFNAME, name) >= 0);
44         assert_se(sd_rtnl_message_append_ether_addr(message, IFLA_ADDRESS, ether_aton(mac)) >= 0);
45         assert_se(sd_rtnl_message_append_u32(message, IFLA_MTU, mtu) >= 0);
46
47         assert_se(sd_rtnl_call(rtnl, message, 0, NULL) == 1);
48         assert_se(sd_rtnl_message_rewind(message) >= 0);
49
50         assert_se(sd_rtnl_message_read_string(message, IFLA_IFNAME, &name_out) >= 0);
51         assert_se(streq(name, name_out));
52
53         assert_se(sd_rtnl_message_read_ether_addr(message, IFLA_ADDRESS, &mac_out) >= 0);
54         assert_se(streq(mac, ether_ntoa(&mac_out)));
55
56         assert_se(sd_rtnl_message_read_u32(message, IFLA_MTU, &mtu_out) >= 0);
57         assert_se(mtu == mtu_out);
58 }
59
60 static void test_link_get(sd_rtnl *rtnl, int ifindex) {
61         sd_rtnl_message *m;
62         sd_rtnl_message *r;
63         unsigned int mtu = 1500;
64         const char *str_data;
65         uint8_t u8_data;
66         uint32_t u32_data;
67         struct ether_addr eth_data;
68
69         assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_GETLINK, ifindex) >= 0);
70         assert_se(m);
71
72         /* u8 test cases  */
73         assert_se(sd_rtnl_message_append_u8(m, IFLA_CARRIER, 0) >= 0);
74         assert_se(sd_rtnl_message_append_u8(m, IFLA_OPERSTATE, 0) >= 0);
75         assert_se(sd_rtnl_message_append_u8(m, IFLA_LINKMODE, 0) >= 0);
76
77         /* u32 test cases */
78         assert_se(sd_rtnl_message_append_u32(m, IFLA_MTU, mtu) >= 0);
79         assert_se(sd_rtnl_message_append_u32(m, IFLA_GROUP, 0) >= 0);
80         assert_se(sd_rtnl_message_append_u32(m, IFLA_TXQLEN, 0) >= 0);
81         assert_se(sd_rtnl_message_append_u32(m, IFLA_NUM_TX_QUEUES, 0) >= 0);
82         assert_se(sd_rtnl_message_append_u32(m, IFLA_NUM_RX_QUEUES, 0) >= 0);
83
84         assert_se(sd_rtnl_call(rtnl, m, -1, &r) == 1);
85
86         assert_se(sd_rtnl_message_read_string(r, IFLA_IFNAME, &str_data) == 0);
87
88         assert_se(sd_rtnl_message_read_u8(r, IFLA_CARRIER, &u8_data) == 0);
89         assert_se(sd_rtnl_message_read_u8(r, IFLA_OPERSTATE, &u8_data) == 0);
90         assert_se(sd_rtnl_message_read_u8(r, IFLA_LINKMODE, &u8_data) == 0);
91
92         assert_se(sd_rtnl_message_read_u32(r, IFLA_MTU, &u32_data) == 0);
93         assert_se(sd_rtnl_message_read_u32(r, IFLA_GROUP, &u32_data) == 0);
94         assert_se(sd_rtnl_message_read_u32(r, IFLA_TXQLEN, &u32_data) == 0);
95         assert_se(sd_rtnl_message_read_u32(r, IFLA_NUM_TX_QUEUES, &u32_data) == 0);
96         assert_se(sd_rtnl_message_read_u32(r, IFLA_NUM_RX_QUEUES, &u32_data) == 0);
97
98         assert_se(sd_rtnl_message_read_ether_addr(r, IFLA_ADDRESS, &eth_data) == 0);
99
100         assert_se(sd_rtnl_flush(rtnl) >= 0);
101         assert_se((m = sd_rtnl_message_unref(m)) == NULL);
102         assert_se((r = sd_rtnl_message_unref(r)) == NULL);
103 }
104
105
106 static void test_address_get(sd_rtnl *rtnl, int ifindex) {
107         sd_rtnl_message *m;
108         sd_rtnl_message *r;
109         struct in_addr in_data;
110         struct ifa_cacheinfo cache;
111         const char *label;
112
113         assert_se(sd_rtnl_message_new_addr(rtnl, &m, RTM_GETADDR, ifindex, AF_INET) >= 0);
114         assert_se(m);
115
116         assert_se(sd_rtnl_call(rtnl, m, -1, &r) == 1);
117
118         assert_se(sd_rtnl_message_read_in_addr(r, IFA_LOCAL, &in_data) == 0);
119         assert_se(sd_rtnl_message_read_in_addr(r, IFA_ADDRESS, &in_data) == 0);
120         assert_se(sd_rtnl_message_read_string(r, IFA_LABEL, &label) == 0);
121         assert_se(sd_rtnl_message_read_cache_info(r, IFA_CACHEINFO, &cache) == 0);
122
123         assert_se(sd_rtnl_flush(rtnl) >= 0);
124         assert_se((m = sd_rtnl_message_unref(m)) == NULL);
125         assert_se((r = sd_rtnl_message_unref(r)) == NULL);
126
127 }
128
129 static void test_route(void) {
130         _cleanup_rtnl_message_unref_ sd_rtnl_message *req;
131         struct in_addr addr, addr_data;
132         uint32_t index = 2, u32_data;
133         int r;
134
135         r = sd_rtnl_message_new_route(NULL, &req, RTM_NEWROUTE, AF_INET, RTPROT_STATIC);
136         if (r < 0) {
137                 log_error("Could not create RTM_NEWROUTE message: %s", strerror(-r));
138                 return;
139         }
140
141         addr.s_addr = htonl(INADDR_LOOPBACK);
142
143         r = sd_rtnl_message_append_in_addr(req, RTA_GATEWAY, &addr);
144         if (r < 0) {
145                 log_error("Could not append RTA_GATEWAY attribute: %s", strerror(-r));
146                 return;
147         }
148
149         r = sd_rtnl_message_append_u32(req, RTA_OIF, index);
150         if (r < 0) {
151                 log_error("Could not append RTA_OIF attribute: %s", strerror(-r));
152                 return;
153         }
154
155         assert_se(sd_rtnl_message_rewind(req) >= 0);
156
157         assert_se(sd_rtnl_message_read_in_addr(req, RTA_GATEWAY, &addr_data) >= 0);
158         assert_se(addr_data.s_addr == addr.s_addr);
159
160         assert_se(sd_rtnl_message_read_u32(req, RTA_OIF, &u32_data) >= 0);
161         assert_se(u32_data == index);
162
163         assert_se((req = sd_rtnl_message_unref(req)) == NULL);
164 }
165
166 static void test_multiple(void) {
167         sd_rtnl *rtnl1, *rtnl2;
168
169         assert_se(sd_rtnl_open(&rtnl1, 0) >= 0);
170         assert_se(sd_rtnl_open(&rtnl2, 0) >= 0);
171
172         rtnl1 = sd_rtnl_unref(rtnl1);
173         rtnl2 = sd_rtnl_unref(rtnl2);
174 }
175
176 static int link_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
177         char *ifname = userdata;
178         const char *data;
179
180         assert_se(rtnl);
181         assert_se(m);
182
183         log_info("got link info about %s", ifname);
184         free(ifname);
185
186         assert_se(sd_rtnl_message_read_string(m, IFLA_IFNAME, &data) >= 0);
187         assert_se(streq(data, "lo"));
188
189         return 1;
190 }
191
192 static void test_event_loop(int ifindex) {
193         _cleanup_event_unref_ sd_event *event = NULL;
194         _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
195         _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
196         char *ifname;
197
198         ifname = strdup("lo2");
199         assert_se(ifname);
200
201         assert_se(sd_rtnl_open(&rtnl, 0) >= 0);
202         assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_GETLINK, ifindex) >= 0);
203
204         assert_se(sd_rtnl_call_async(rtnl, m, &link_handler, ifname, 0, NULL) >= 0);
205
206         assert_se(sd_event_default(&event) >= 0);
207
208         assert_se(sd_rtnl_attach_event(rtnl, event, 0) >= 0);
209
210         assert_se(sd_event_run(event, 0) >= 0);
211
212         assert_se(sd_rtnl_detach_event(rtnl) >= 0);
213
214         assert_se((rtnl = sd_rtnl_unref(rtnl)) == NULL);
215 }
216
217 static int pipe_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
218         int *counter = userdata;
219         int r;
220
221         (*counter) --;
222
223         r = sd_rtnl_message_get_errno(m);
224
225         log_info("%d left in pipe. got reply: %s", *counter, strerror(-r));
226
227         assert_se(r >= 0);
228
229         return 1;
230 }
231
232 static void test_async(int ifindex) {
233         _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
234         _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL, *r = NULL;
235         uint32_t serial;
236         char *ifname;
237
238         ifname = strdup("lo");
239         assert_se(ifname);
240
241         assert_se(sd_rtnl_open(&rtnl, 0) >= 0);
242
243         assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_GETLINK, ifindex) >= 0);
244
245         assert_se(sd_rtnl_call_async(rtnl, m, &link_handler, ifname, 0, &serial) >= 0);
246
247         assert_se(sd_rtnl_wait(rtnl, 0) >= 0);
248         assert_se(sd_rtnl_process(rtnl, &r) >= 0);
249
250         assert_se((rtnl = sd_rtnl_unref(rtnl)) == NULL);
251 }
252
253 static void test_pipe(int ifindex) {
254         _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
255         _cleanup_rtnl_message_unref_ sd_rtnl_message *m1 = NULL, *m2 = NULL;
256         int counter = 0;
257
258         assert_se(sd_rtnl_open(&rtnl, 0) >= 0);
259
260         assert_se(sd_rtnl_message_new_link(rtnl, &m1, RTM_GETLINK, ifindex) >= 0);
261         assert_se(sd_rtnl_message_new_link(rtnl, &m2, RTM_GETLINK, ifindex) >= 0);
262
263         counter ++;
264         assert_se(sd_rtnl_call_async(rtnl, m1, &pipe_handler, &counter, 0, NULL) >= 0);
265
266         counter ++;
267         assert_se(sd_rtnl_call_async(rtnl, m2, &pipe_handler, &counter, 0, NULL) >= 0);
268
269         while (counter > 0) {
270                 assert_se(sd_rtnl_wait(rtnl, 0) >= 0);
271                 assert_se(sd_rtnl_process(rtnl, NULL) >= 0);
272         }
273
274         assert_se((rtnl = sd_rtnl_unref(rtnl)) == NULL);
275 }
276
277 static void test_container(void) {
278         _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
279         uint16_t u16_data;
280         uint32_t u32_data;
281         const char *string_data;
282
283         assert_se(sd_rtnl_message_new_link(NULL, &m, RTM_NEWLINK, 0) >= 0);
284
285         assert_se(sd_rtnl_message_open_container(m, IFLA_LINKINFO) >= 0);
286         assert_se(sd_rtnl_message_open_container_union(m, IFLA_INFO_DATA, "vlan") >= 0);
287         assert_se(sd_rtnl_message_append_u16(m, IFLA_VLAN_ID, 100) >= 0);
288         assert_se(sd_rtnl_message_close_container(m) >= 0);
289         assert_se(sd_rtnl_message_append_string(m, IFLA_INFO_KIND, "vlan") >= 0);
290         assert_se(sd_rtnl_message_close_container(m) >= 0);
291         assert_se(sd_rtnl_message_close_container(m) == -EINVAL);
292
293         assert_se(sd_rtnl_message_rewind(m) >= 0);
294
295         assert_se(sd_rtnl_message_enter_container(m, IFLA_LINKINFO) >= 0);
296         assert_se(sd_rtnl_message_read_string(m, IFLA_INFO_KIND, &string_data) >= 0);
297         assert_se(streq("vlan", string_data));
298
299         assert_se(sd_rtnl_message_enter_container(m, IFLA_INFO_DATA) >= 0);
300         assert_se(sd_rtnl_message_read_u16(m, IFLA_VLAN_ID, &u16_data) >= 0);
301         assert_se(sd_rtnl_message_exit_container(m) >= 0);
302
303         assert_se(sd_rtnl_message_read_string(m, IFLA_INFO_KIND, &string_data) >= 0);
304         assert_se(streq("vlan", string_data));
305         assert_se(sd_rtnl_message_exit_container(m) >= 0);
306
307         assert_se(sd_rtnl_message_read_u32(m, IFLA_LINKINFO, &u32_data) < 0);
308
309         assert_se(sd_rtnl_message_exit_container(m) == -EINVAL);
310 }
311
312 static void test_match(void) {
313         _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
314
315         assert_se(sd_rtnl_open(&rtnl, 0) >= 0);
316
317         assert_se(sd_rtnl_add_match(rtnl, RTM_NEWLINK, &link_handler, NULL) >= 0);
318         assert_se(sd_rtnl_add_match(rtnl, RTM_NEWLINK, &link_handler, NULL) >= 0);
319
320         assert_se(sd_rtnl_remove_match(rtnl, RTM_NEWLINK, &link_handler, NULL) == 1);
321         assert_se(sd_rtnl_remove_match(rtnl, RTM_NEWLINK, &link_handler, NULL) == 1);
322         assert_se(sd_rtnl_remove_match(rtnl, RTM_NEWLINK, &link_handler, NULL) == 0);
323
324         assert_se((rtnl = sd_rtnl_unref(rtnl)) == NULL);
325 }
326
327 static void test_get_addresses(sd_rtnl *rtnl) {
328         _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
329         sd_rtnl_message *m;
330
331         assert_se(sd_rtnl_message_new_addr(rtnl, &req, RTM_GETADDR, 0, AF_UNSPEC) >= 0);
332
333         assert_se(sd_rtnl_call(rtnl, req, 0, &reply) >= 0);
334
335         for (m = reply; m; m = sd_rtnl_message_next(m)) {
336                 uint16_t type;
337                 unsigned char scope, flags;
338                 int family, ifindex;
339
340                 assert_se(sd_rtnl_message_get_type(m, &type) >= 0);
341                 assert_se(type == RTM_NEWADDR);
342
343                 assert_se(sd_rtnl_message_addr_get_ifindex(m, &ifindex) >= 0);
344                 assert_se(sd_rtnl_message_addr_get_family(m, &family) >= 0);
345                 assert_se(sd_rtnl_message_addr_get_scope(m, &scope) >= 0);
346                 assert_se(sd_rtnl_message_addr_get_flags(m, &flags) >= 0);
347
348                 assert_se(ifindex > 0);
349                 assert_se(family == AF_INET || family == AF_INET6);
350
351                 log_info("got IPv%u address on ifindex %i", family == AF_INET ? 4: 6, ifindex);
352         }
353 }
354
355 int main(void) {
356         sd_rtnl *rtnl;
357         sd_rtnl_message *m;
358         sd_rtnl_message *r;
359         const char *string_data;
360         int if_loopback;
361         uint16_t type;
362
363         test_match();
364
365         test_multiple();
366
367         test_route();
368
369         test_container();
370
371         assert_se(sd_rtnl_open(&rtnl, 0) >= 0);
372         assert_se(rtnl);
373
374         if_loopback = (int) if_nametoindex("lo");
375         assert_se(if_loopback > 0);
376
377         test_async(if_loopback);
378
379         test_pipe(if_loopback);
380
381         test_event_loop(if_loopback);
382
383         test_link_configure(rtnl, if_loopback);
384
385         test_get_addresses(rtnl);
386
387         assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_GETLINK, if_loopback) >= 0);
388         assert_se(m);
389
390         assert_se(sd_rtnl_message_get_type(m, &type) >= 0);
391         assert_se(type == RTM_GETLINK);
392
393         assert_se(sd_rtnl_message_read_string(m, IFLA_IFNAME, &string_data) == -EPERM);
394
395         assert_se(sd_rtnl_call(rtnl, m, 0, &r) == 1);
396         assert_se(sd_rtnl_message_get_type(r, &type) >= 0);
397         assert_se(type == RTM_NEWLINK);
398
399         assert_se((r = sd_rtnl_message_unref(r)) == NULL);
400
401         assert_se(sd_rtnl_call(rtnl, m, -1, &r) == -EPERM);
402         assert_se((m = sd_rtnl_message_unref(m)) == NULL);
403         assert_se((r = sd_rtnl_message_unref(r)) == NULL);
404
405         test_link_get(rtnl, if_loopback);
406         test_address_get(rtnl, if_loopback);
407
408         assert_se(sd_rtnl_flush(rtnl) >= 0);
409         assert_se((m = sd_rtnl_message_unref(m)) == NULL);
410         assert_se((r = sd_rtnl_message_unref(r)) == NULL);
411         assert_se((rtnl = sd_rtnl_unref(rtnl)) == NULL);
412
413         return EXIT_SUCCESS;
414 }