]> git.proxmox.com Git - systemd.git/blob - src/libsystemd/sd-rtnl/test-rtnl.c
Imported Upstream version 217
[systemd.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("Could not create RTM_NEWROUTE message: %s", strerror(-r));
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("Could not append RTA_GATEWAY attribute: %s", strerror(-r));
147 return;
148 }
149
150 r = sd_rtnl_message_append_u32(req, RTA_OIF, index);
151 if (r < 0) {
152 log_error("Could not append RTA_OIF attribute: %s", strerror(-r));
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("%d left in pipe. got reply: %s", *counter, strerror(-r));
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 }