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