]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd/sd-netlink/test-netlink.c
Add SPDX license identifiers to source files under the LGPL
[thirdparty/systemd.git] / src / libsystemd / sd-netlink / test-netlink.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /***
3 This file is part of systemd.
4
5 Copyright 2013 Tom Gundersen <teg@jklm.no>
6
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19 ***/
20
21 #include <net/if.h>
22 #include <netinet/ether.h>
23
24 #include "sd-netlink.h"
25
26 #include "ether-addr-util.h"
27 #include "macro.h"
28 #include "missing.h"
29 #include "netlink-util.h"
30 #include "socket-util.h"
31 #include "string-util.h"
32 #include "util.h"
33
34 static void test_message_link_bridge(sd_netlink *rtnl) {
35 _cleanup_(sd_netlink_message_unrefp) sd_netlink_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_netlink_message_open_container(message, IFLA_PROTINFO) >= 0);
41 assert_se(sd_netlink_message_append_u32(message, IFLA_BRPORT_COST, 10) >= 0);
42 assert_se(sd_netlink_message_close_container(message) >= 0);
43
44 assert_se(sd_netlink_message_rewind(message) >= 0);
45
46 assert_se(sd_netlink_message_enter_container(message, IFLA_PROTINFO) >= 0);
47 assert_se(sd_netlink_message_read_u32(message, IFLA_BRPORT_COST, &cost) >= 0);
48 assert_se(cost == 10);
49 assert_se(sd_netlink_message_exit_container(message) >= 0);
50 }
51
52 static void test_link_configure(sd_netlink *rtnl, int ifindex) {
53 _cleanup_(sd_netlink_message_unrefp) sd_netlink_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_netlink_message_append_string(message, IFLA_IFNAME, name) >= 0);
63 assert_se(sd_netlink_message_append_ether_addr(message, IFLA_ADDRESS, ether_aton(mac)) >= 0);
64 assert_se(sd_netlink_message_append_u32(message, IFLA_MTU, mtu) >= 0);
65
66 assert_se(sd_netlink_call(rtnl, message, 0, NULL) == 1);
67 assert_se(sd_netlink_message_rewind(message) >= 0);
68
69 assert_se(sd_netlink_message_read_string(message, IFLA_IFNAME, &name_out) >= 0);
70 assert_se(streq(name, name_out));
71
72 assert_se(sd_netlink_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_netlink_message_read_u32(message, IFLA_MTU, &mtu_out) >= 0);
76 assert_se(mtu == mtu_out);
77 }
78
79 static void test_link_get(sd_netlink *rtnl, int ifindex) {
80 sd_netlink_message *m;
81 sd_netlink_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_netlink_message_append_u8(m, IFLA_CARRIER, 0) >= 0);
93 assert_se(sd_netlink_message_append_u8(m, IFLA_OPERSTATE, 0) >= 0);
94 assert_se(sd_netlink_message_append_u8(m, IFLA_LINKMODE, 0) >= 0);
95
96 /* u32 test cases */
97 assert_se(sd_netlink_message_append_u32(m, IFLA_MTU, mtu) >= 0);
98 assert_se(sd_netlink_message_append_u32(m, IFLA_GROUP, 0) >= 0);
99 assert_se(sd_netlink_message_append_u32(m, IFLA_TXQLEN, 0) >= 0);
100 assert_se(sd_netlink_message_append_u32(m, IFLA_NUM_TX_QUEUES, 0) >= 0);
101 assert_se(sd_netlink_message_append_u32(m, IFLA_NUM_RX_QUEUES, 0) >= 0);
102
103 assert_se(sd_netlink_call(rtnl, m, -1, &r) == 1);
104
105 assert_se(sd_netlink_message_read_string(r, IFLA_IFNAME, &str_data) == 0);
106
107 assert_se(sd_netlink_message_read_u8(r, IFLA_CARRIER, &u8_data) == 0);
108 assert_se(sd_netlink_message_read_u8(r, IFLA_OPERSTATE, &u8_data) == 0);
109 assert_se(sd_netlink_message_read_u8(r, IFLA_LINKMODE, &u8_data) == 0);
110
111 assert_se(sd_netlink_message_read_u32(r, IFLA_MTU, &u32_data) == 0);
112 assert_se(sd_netlink_message_read_u32(r, IFLA_GROUP, &u32_data) == 0);
113 assert_se(sd_netlink_message_read_u32(r, IFLA_TXQLEN, &u32_data) == 0);
114 assert_se(sd_netlink_message_read_u32(r, IFLA_NUM_TX_QUEUES, &u32_data) == 0);
115 assert_se(sd_netlink_message_read_u32(r, IFLA_NUM_RX_QUEUES, &u32_data) == 0);
116
117 assert_se(sd_netlink_message_read_ether_addr(r, IFLA_ADDRESS, &eth_data) == 0);
118
119 assert_se((m = sd_netlink_message_unref(m)) == NULL);
120 assert_se((r = sd_netlink_message_unref(r)) == NULL);
121 }
122
123
124 static void test_address_get(sd_netlink *rtnl, int ifindex) {
125 sd_netlink_message *m;
126 sd_netlink_message *r;
127 struct in_addr in_data;
128 struct ifa_cacheinfo cache;
129 const char *label;
130
131 assert_se(sd_rtnl_message_new_addr(rtnl, &m, RTM_GETADDR, ifindex, AF_INET) >= 0);
132 assert_se(m);
133
134 assert_se(sd_netlink_call(rtnl, m, -1, &r) == 1);
135
136 assert_se(sd_netlink_message_read_in_addr(r, IFA_LOCAL, &in_data) == 0);
137 assert_se(sd_netlink_message_read_in_addr(r, IFA_ADDRESS, &in_data) == 0);
138 assert_se(sd_netlink_message_read_string(r, IFA_LABEL, &label) == 0);
139 assert_se(sd_netlink_message_read_cache_info(r, IFA_CACHEINFO, &cache) == 0);
140
141 assert_se((m = sd_netlink_message_unref(m)) == NULL);
142 assert_se((r = sd_netlink_message_unref(r)) == NULL);
143
144 }
145
146 static void test_route(void) {
147 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req;
148 struct in_addr addr, addr_data;
149 uint32_t index = 2, u32_data;
150 int r;
151
152 r = sd_rtnl_message_new_route(NULL, &req, RTM_NEWROUTE, AF_INET, RTPROT_STATIC);
153 if (r < 0) {
154 log_error_errno(r, "Could not create RTM_NEWROUTE message: %m");
155 return;
156 }
157
158 addr.s_addr = htonl(INADDR_LOOPBACK);
159
160 r = sd_netlink_message_append_in_addr(req, RTA_GATEWAY, &addr);
161 if (r < 0) {
162 log_error_errno(r, "Could not append RTA_GATEWAY attribute: %m");
163 return;
164 }
165
166 r = sd_netlink_message_append_u32(req, RTA_OIF, index);
167 if (r < 0) {
168 log_error_errno(r, "Could not append RTA_OIF attribute: %m");
169 return;
170 }
171
172 assert_se(sd_netlink_message_rewind(req) >= 0);
173
174 assert_se(sd_netlink_message_read_in_addr(req, RTA_GATEWAY, &addr_data) >= 0);
175 assert_se(addr_data.s_addr == addr.s_addr);
176
177 assert_se(sd_netlink_message_read_u32(req, RTA_OIF, &u32_data) >= 0);
178 assert_se(u32_data == index);
179
180 assert_se((req = sd_netlink_message_unref(req)) == NULL);
181 }
182
183 static void test_multiple(void) {
184 sd_netlink *rtnl1, *rtnl2;
185
186 assert_se(sd_netlink_open(&rtnl1) >= 0);
187 assert_se(sd_netlink_open(&rtnl2) >= 0);
188
189 rtnl1 = sd_netlink_unref(rtnl1);
190 rtnl2 = sd_netlink_unref(rtnl2);
191 }
192
193 static int link_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
194 char *ifname = userdata;
195 const char *data;
196
197 assert_se(rtnl);
198 assert_se(m);
199
200 log_info("got link info about %s", ifname);
201 free(ifname);
202
203 assert_se(sd_netlink_message_read_string(m, IFLA_IFNAME, &data) >= 0);
204 assert_se(streq(data, "lo"));
205
206 return 1;
207 }
208
209 static void test_event_loop(int ifindex) {
210 _cleanup_(sd_event_unrefp) sd_event *event = NULL;
211 _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
212 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
213 char *ifname;
214
215 ifname = strdup("lo2");
216 assert_se(ifname);
217
218 assert_se(sd_netlink_open(&rtnl) >= 0);
219 assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_GETLINK, ifindex) >= 0);
220
221 assert_se(sd_netlink_call_async(rtnl, m, link_handler, ifname, 0, NULL) >= 0);
222
223 assert_se(sd_event_default(&event) >= 0);
224
225 assert_se(sd_netlink_attach_event(rtnl, event, 0) >= 0);
226
227 assert_se(sd_event_run(event, 0) >= 0);
228
229 assert_se(sd_netlink_detach_event(rtnl) >= 0);
230
231 assert_se((rtnl = sd_netlink_unref(rtnl)) == NULL);
232 }
233
234 static int pipe_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
235 int *counter = userdata;
236 int r;
237
238 (*counter)--;
239
240 r = sd_netlink_message_get_errno(m);
241
242 log_info_errno(r, "%d left in pipe. got reply: %m", *counter);
243
244 assert_se(r >= 0);
245
246 return 1;
247 }
248
249 static void test_async(int ifindex) {
250 _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
251 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL, *r = NULL;
252 uint32_t serial;
253 char *ifname;
254
255 ifname = strdup("lo");
256 assert_se(ifname);
257
258 assert_se(sd_netlink_open(&rtnl) >= 0);
259
260 assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_GETLINK, ifindex) >= 0);
261
262 assert_se(sd_netlink_call_async(rtnl, m, link_handler, ifname, 0, &serial) >= 0);
263
264 assert_se(sd_netlink_wait(rtnl, 0) >= 0);
265 assert_se(sd_netlink_process(rtnl, &r) >= 0);
266
267 assert_se((rtnl = sd_netlink_unref(rtnl)) == NULL);
268 }
269
270 static void test_pipe(int ifindex) {
271 _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
272 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m1 = NULL, *m2 = NULL;
273 int counter = 0;
274
275 assert_se(sd_netlink_open(&rtnl) >= 0);
276
277 assert_se(sd_rtnl_message_new_link(rtnl, &m1, RTM_GETLINK, ifindex) >= 0);
278 assert_se(sd_rtnl_message_new_link(rtnl, &m2, RTM_GETLINK, ifindex) >= 0);
279
280 counter++;
281 assert_se(sd_netlink_call_async(rtnl, m1, pipe_handler, &counter, 0, NULL) >= 0);
282
283 counter++;
284 assert_se(sd_netlink_call_async(rtnl, m2, pipe_handler, &counter, 0, NULL) >= 0);
285
286 while (counter > 0) {
287 assert_se(sd_netlink_wait(rtnl, 0) >= 0);
288 assert_se(sd_netlink_process(rtnl, NULL) >= 0);
289 }
290
291 assert_se((rtnl = sd_netlink_unref(rtnl)) == NULL);
292 }
293
294 static void test_container(void) {
295 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
296 uint16_t u16_data;
297 uint32_t u32_data;
298 const char *string_data;
299
300 assert_se(sd_rtnl_message_new_link(NULL, &m, RTM_NEWLINK, 0) >= 0);
301
302 assert_se(sd_netlink_message_open_container(m, IFLA_LINKINFO) >= 0);
303 assert_se(sd_netlink_message_open_container_union(m, IFLA_INFO_DATA, "vlan") >= 0);
304 assert_se(sd_netlink_message_append_u16(m, IFLA_VLAN_ID, 100) >= 0);
305 assert_se(sd_netlink_message_close_container(m) >= 0);
306 assert_se(sd_netlink_message_append_string(m, IFLA_INFO_KIND, "vlan") >= 0);
307 assert_se(sd_netlink_message_close_container(m) >= 0);
308 assert_se(sd_netlink_message_close_container(m) == -EINVAL);
309
310 assert_se(sd_netlink_message_rewind(m) >= 0);
311
312 assert_se(sd_netlink_message_enter_container(m, IFLA_LINKINFO) >= 0);
313 assert_se(sd_netlink_message_read_string(m, IFLA_INFO_KIND, &string_data) >= 0);
314 assert_se(streq("vlan", string_data));
315
316 assert_se(sd_netlink_message_enter_container(m, IFLA_INFO_DATA) >= 0);
317 assert_se(sd_netlink_message_read_u16(m, IFLA_VLAN_ID, &u16_data) >= 0);
318 assert_se(sd_netlink_message_exit_container(m) >= 0);
319
320 assert_se(sd_netlink_message_read_string(m, IFLA_INFO_KIND, &string_data) >= 0);
321 assert_se(streq("vlan", string_data));
322 assert_se(sd_netlink_message_exit_container(m) >= 0);
323
324 assert_se(sd_netlink_message_read_u32(m, IFLA_LINKINFO, &u32_data) < 0);
325
326 assert_se(sd_netlink_message_exit_container(m) == -EINVAL);
327 }
328
329 static void test_match(void) {
330 _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
331
332 assert_se(sd_netlink_open(&rtnl) >= 0);
333
334 assert_se(sd_netlink_add_match(rtnl, RTM_NEWLINK, link_handler, NULL) >= 0);
335 assert_se(sd_netlink_add_match(rtnl, RTM_NEWLINK, link_handler, NULL) >= 0);
336
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) == 1);
339 assert_se(sd_netlink_remove_match(rtnl, RTM_NEWLINK, link_handler, NULL) == 0);
340
341 assert_se((rtnl = sd_netlink_unref(rtnl)) == NULL);
342 }
343
344 static void test_get_addresses(sd_netlink *rtnl) {
345 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
346 sd_netlink_message *m;
347
348 assert_se(sd_rtnl_message_new_addr(rtnl, &req, RTM_GETADDR, 0, AF_UNSPEC) >= 0);
349
350 assert_se(sd_netlink_call(rtnl, req, 0, &reply) >= 0);
351
352 for (m = reply; m; m = sd_netlink_message_next(m)) {
353 uint16_t type;
354 unsigned char scope, flags;
355 int family, ifindex;
356
357 assert_se(sd_netlink_message_get_type(m, &type) >= 0);
358 assert_se(type == RTM_NEWADDR);
359
360 assert_se(sd_rtnl_message_addr_get_ifindex(m, &ifindex) >= 0);
361 assert_se(sd_rtnl_message_addr_get_family(m, &family) >= 0);
362 assert_se(sd_rtnl_message_addr_get_scope(m, &scope) >= 0);
363 assert_se(sd_rtnl_message_addr_get_flags(m, &flags) >= 0);
364
365 assert_se(ifindex > 0);
366 assert_se(IN_SET(family, AF_INET, AF_INET6));
367
368 log_info("got IPv%u address on ifindex %i", family == AF_INET ? 4: 6, ifindex);
369 }
370 }
371
372 static void test_message(void) {
373 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
374
375 assert_se(rtnl_message_new_synthetic_error(-ETIMEDOUT, 1, &m) >= 0);
376 assert_se(sd_netlink_message_get_errno(m) == -ETIMEDOUT);
377 }
378
379 int main(void) {
380 sd_netlink *rtnl;
381 sd_netlink_message *m;
382 sd_netlink_message *r;
383 const char *string_data;
384 int if_loopback;
385 uint16_t type;
386
387 test_message();
388
389 test_match();
390
391 test_multiple();
392
393 test_route();
394
395 test_container();
396
397 assert_se(sd_netlink_open(&rtnl) >= 0);
398 assert_se(rtnl);
399
400 if_loopback = (int) if_nametoindex("lo");
401 assert_se(if_loopback > 0);
402
403 test_async(if_loopback);
404
405 test_pipe(if_loopback);
406
407 test_event_loop(if_loopback);
408
409 test_link_configure(rtnl, if_loopback);
410
411 test_get_addresses(rtnl);
412
413 test_message_link_bridge(rtnl);
414
415 assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_GETLINK, if_loopback) >= 0);
416 assert_se(m);
417
418 assert_se(sd_netlink_message_get_type(m, &type) >= 0);
419 assert_se(type == RTM_GETLINK);
420
421 assert_se(sd_netlink_message_read_string(m, IFLA_IFNAME, &string_data) == -EPERM);
422
423 assert_se(sd_netlink_call(rtnl, m, 0, &r) == 1);
424 assert_se(sd_netlink_message_get_type(r, &type) >= 0);
425 assert_se(type == RTM_NEWLINK);
426
427 assert_se((r = sd_netlink_message_unref(r)) == NULL);
428
429 assert_se(sd_netlink_call(rtnl, m, -1, &r) == -EPERM);
430 assert_se((m = sd_netlink_message_unref(m)) == NULL);
431 assert_se((r = sd_netlink_message_unref(r)) == NULL);
432
433 test_link_get(rtnl, if_loopback);
434 test_address_get(rtnl, if_loopback);
435
436 assert_se((m = sd_netlink_message_unref(m)) == NULL);
437 assert_se((r = sd_netlink_message_unref(r)) == NULL);
438 assert_se((rtnl = sd_netlink_unref(rtnl)) == NULL);
439
440 return EXIT_SUCCESS;
441 }