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