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