chiark / gitweb /
72d8fe2273c2d85bb7f9849de16975dfe2a01118
[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 int main(void) {
357         sd_rtnl *rtnl;
358         sd_rtnl_message *m;
359         sd_rtnl_message *r;
360         const char *string_data;
361         int if_loopback;
362         uint16_t type;
363
364         test_match();
365
366         test_multiple();
367
368         test_route();
369
370         test_container();
371
372         assert_se(sd_rtnl_open(&rtnl, 0) >= 0);
373         assert_se(rtnl);
374
375         if_loopback = (int) if_nametoindex("lo");
376         assert_se(if_loopback > 0);
377
378         test_async(if_loopback);
379
380         test_pipe(if_loopback);
381
382         test_event_loop(if_loopback);
383
384         test_link_configure(rtnl, if_loopback);
385
386         test_get_addresses(rtnl);
387
388         assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_GETLINK, if_loopback) >= 0);
389         assert_se(m);
390
391         assert_se(sd_rtnl_message_get_type(m, &type) >= 0);
392         assert_se(type == RTM_GETLINK);
393
394         assert_se(sd_rtnl_message_read_string(m, IFLA_IFNAME, &string_data) == -EPERM);
395
396         assert_se(sd_rtnl_call(rtnl, m, 0, &r) == 1);
397         assert_se(sd_rtnl_message_get_type(r, &type) >= 0);
398         assert_se(type == RTM_NEWLINK);
399
400         assert_se((r = sd_rtnl_message_unref(r)) == NULL);
401
402         assert_se(sd_rtnl_call(rtnl, m, -1, &r) == -EPERM);
403         assert_se((m = sd_rtnl_message_unref(m)) == NULL);
404         assert_se((r = sd_rtnl_message_unref(r)) == NULL);
405
406         test_link_get(rtnl, if_loopback);
407         test_address_get(rtnl, if_loopback);
408
409         assert_se(sd_rtnl_flush(rtnl) >= 0);
410         assert_se((m = sd_rtnl_message_unref(m)) == NULL);
411         assert_se((r = sd_rtnl_message_unref(r)) == NULL);
412         assert_se((rtnl = sd_rtnl_unref(rtnl)) == NULL);
413
414         return EXIT_SUCCESS;
415 }