]>
Commit | Line | Data |
---|---|---|
a032b68d | 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ |
86f210e9 | 2 | |
86f210e9 | 3 | #include <net/if.h> |
db2df898 | 4 | #include <netinet/ether.h> |
f2dec872 | 5 | #include <linux/genetlink.h> |
86f210e9 | 6 | |
86f210e9 | 7 | #include "sd-netlink.h" |
db2df898 | 8 | |
6e866b33 | 9 | #include "alloc-util.h" |
db2df898 | 10 | #include "ether-addr-util.h" |
db2df898 | 11 | #include "macro.h" |
db2df898 MP |
12 | #include "netlink-util.h" |
13 | #include "socket-util.h" | |
f2dec872 | 14 | #include "stdio-util.h" |
db2df898 | 15 | #include "string-util.h" |
46cdbd49 | 16 | #include "strv.h" |
db2df898 | 17 | #include "util.h" |
86f210e9 MP |
18 | |
19 | static void test_message_link_bridge(sd_netlink *rtnl) { | |
4c89c718 | 20 | _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *message = NULL; |
86f210e9 MP |
21 | uint32_t cost; |
22 | ||
23 | assert_se(sd_rtnl_message_new_link(rtnl, &message, RTM_NEWLINK, 1) >= 0); | |
a032b68d | 24 | assert_se(sd_rtnl_message_link_set_family(message, AF_BRIDGE) >= 0); |
86f210e9 MP |
25 | assert_se(sd_netlink_message_open_container(message, IFLA_PROTINFO) >= 0); |
26 | assert_se(sd_netlink_message_append_u32(message, IFLA_BRPORT_COST, 10) >= 0); | |
27 | assert_se(sd_netlink_message_close_container(message) >= 0); | |
28 | ||
e1f67bc7 | 29 | assert_se(sd_netlink_message_rewind(message, NULL) >= 0); |
86f210e9 MP |
30 | |
31 | assert_se(sd_netlink_message_enter_container(message, IFLA_PROTINFO) >= 0); | |
32 | assert_se(sd_netlink_message_read_u32(message, IFLA_BRPORT_COST, &cost) >= 0); | |
33 | assert_se(cost == 10); | |
34 | assert_se(sd_netlink_message_exit_container(message) >= 0); | |
35 | } | |
36 | ||
37 | static void test_link_configure(sd_netlink *rtnl, int ifindex) { | |
8b3d4ff0 MB |
38 | _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *message = NULL, *reply = NULL; |
39 | uint32_t mtu_out; | |
86f210e9 MP |
40 | const char *name_out; |
41 | struct ether_addr mac_out; | |
42 | ||
43 | /* we'd really like to test NEWLINK, but let's not mess with the running kernel */ | |
44 | assert_se(sd_rtnl_message_new_link(rtnl, &message, RTM_GETLINK, ifindex) >= 0); | |
86f210e9 | 45 | |
8b3d4ff0 | 46 | assert_se(sd_netlink_call(rtnl, message, 0, &reply) == 1); |
86f210e9 | 47 | |
8b3d4ff0 MB |
48 | assert_se(sd_netlink_message_read_string(reply, IFLA_IFNAME, &name_out) >= 0); |
49 | assert_se(sd_netlink_message_read_ether_addr(reply, IFLA_ADDRESS, &mac_out) >= 0); | |
50 | assert_se(sd_netlink_message_read_u32(reply, IFLA_MTU, &mtu_out) >= 0); | |
86f210e9 MP |
51 | } |
52 | ||
53 | static void test_link_get(sd_netlink *rtnl, int ifindex) { | |
8b3d4ff0 | 54 | _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL, *r = NULL; |
86f210e9 MP |
55 | const char *str_data; |
56 | uint8_t u8_data; | |
57 | uint32_t u32_data; | |
58 | struct ether_addr eth_data; | |
59 | ||
60 | assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_GETLINK, ifindex) >= 0); | |
61 | assert_se(m); | |
62 | ||
8b3d4ff0 | 63 | assert_se(sd_netlink_call(rtnl, m, 0, &r) == 1); |
86f210e9 MP |
64 | |
65 | assert_se(sd_netlink_message_read_string(r, IFLA_IFNAME, &str_data) == 0); | |
66 | ||
67 | assert_se(sd_netlink_message_read_u8(r, IFLA_CARRIER, &u8_data) == 0); | |
68 | assert_se(sd_netlink_message_read_u8(r, IFLA_OPERSTATE, &u8_data) == 0); | |
69 | assert_se(sd_netlink_message_read_u8(r, IFLA_LINKMODE, &u8_data) == 0); | |
70 | ||
71 | assert_se(sd_netlink_message_read_u32(r, IFLA_MTU, &u32_data) == 0); | |
72 | assert_se(sd_netlink_message_read_u32(r, IFLA_GROUP, &u32_data) == 0); | |
73 | assert_se(sd_netlink_message_read_u32(r, IFLA_TXQLEN, &u32_data) == 0); | |
74 | assert_se(sd_netlink_message_read_u32(r, IFLA_NUM_TX_QUEUES, &u32_data) == 0); | |
75 | assert_se(sd_netlink_message_read_u32(r, IFLA_NUM_RX_QUEUES, &u32_data) == 0); | |
76 | ||
77 | assert_se(sd_netlink_message_read_ether_addr(r, IFLA_ADDRESS, ð_data) == 0); | |
86f210e9 MP |
78 | } |
79 | ||
86f210e9 | 80 | static void test_address_get(sd_netlink *rtnl, int ifindex) { |
8b3d4ff0 | 81 | _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL, *r = NULL; |
86f210e9 MP |
82 | struct in_addr in_data; |
83 | struct ifa_cacheinfo cache; | |
84 | const char *label; | |
85 | ||
86 | assert_se(sd_rtnl_message_new_addr(rtnl, &m, RTM_GETADDR, ifindex, AF_INET) >= 0); | |
87 | assert_se(m); | |
8b3d4ff0 | 88 | assert_se(sd_netlink_message_request_dump(m, true) >= 0); |
86f210e9 MP |
89 | assert_se(sd_netlink_call(rtnl, m, -1, &r) == 1); |
90 | ||
91 | assert_se(sd_netlink_message_read_in_addr(r, IFA_LOCAL, &in_data) == 0); | |
92 | assert_se(sd_netlink_message_read_in_addr(r, IFA_ADDRESS, &in_data) == 0); | |
93 | assert_se(sd_netlink_message_read_string(r, IFA_LABEL, &label) == 0); | |
94 | assert_se(sd_netlink_message_read_cache_info(r, IFA_CACHEINFO, &cache) == 0); | |
86f210e9 MP |
95 | } |
96 | ||
1d42b86d | 97 | static void test_route(sd_netlink *rtnl) { |
20a6e51f | 98 | _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; |
86f210e9 MP |
99 | struct in_addr addr, addr_data; |
100 | uint32_t index = 2, u32_data; | |
101 | int r; | |
102 | ||
1d42b86d | 103 | r = sd_rtnl_message_new_route(rtnl, &req, RTM_NEWROUTE, AF_INET, RTPROT_STATIC); |
86f210e9 MP |
104 | if (r < 0) { |
105 | log_error_errno(r, "Could not create RTM_NEWROUTE message: %m"); | |
106 | return; | |
107 | } | |
108 | ||
a032b68d | 109 | addr.s_addr = htobe32(INADDR_LOOPBACK); |
86f210e9 MP |
110 | |
111 | r = sd_netlink_message_append_in_addr(req, RTA_GATEWAY, &addr); | |
112 | if (r < 0) { | |
113 | log_error_errno(r, "Could not append RTA_GATEWAY attribute: %m"); | |
114 | return; | |
115 | } | |
116 | ||
117 | r = sd_netlink_message_append_u32(req, RTA_OIF, index); | |
118 | if (r < 0) { | |
119 | log_error_errno(r, "Could not append RTA_OIF attribute: %m"); | |
120 | return; | |
121 | } | |
122 | ||
e1f67bc7 | 123 | assert_se(sd_netlink_message_rewind(req, NULL) >= 0); |
86f210e9 MP |
124 | |
125 | assert_se(sd_netlink_message_read_in_addr(req, RTA_GATEWAY, &addr_data) >= 0); | |
126 | assert_se(addr_data.s_addr == addr.s_addr); | |
127 | ||
128 | assert_se(sd_netlink_message_read_u32(req, RTA_OIF, &u32_data) >= 0); | |
129 | assert_se(u32_data == index); | |
130 | ||
131 | assert_se((req = sd_netlink_message_unref(req)) == NULL); | |
132 | } | |
133 | ||
134 | static void test_multiple(void) { | |
135 | sd_netlink *rtnl1, *rtnl2; | |
136 | ||
137 | assert_se(sd_netlink_open(&rtnl1) >= 0); | |
138 | assert_se(sd_netlink_open(&rtnl2) >= 0); | |
139 | ||
140 | rtnl1 = sd_netlink_unref(rtnl1); | |
141 | rtnl2 = sd_netlink_unref(rtnl2); | |
142 | } | |
143 | ||
144 | static int link_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) { | |
145 | char *ifname = userdata; | |
146 | const char *data; | |
147 | ||
148 | assert_se(rtnl); | |
149 | assert_se(m); | |
6e866b33 | 150 | assert_se(userdata); |
86f210e9 | 151 | |
6e866b33 | 152 | log_info("%s: got link info about %s", __func__, ifname); |
86f210e9 MP |
153 | free(ifname); |
154 | ||
155 | assert_se(sd_netlink_message_read_string(m, IFLA_IFNAME, &data) >= 0); | |
156 | assert_se(streq(data, "lo")); | |
157 | ||
158 | return 1; | |
159 | } | |
160 | ||
161 | static void test_event_loop(int ifindex) { | |
4c89c718 MP |
162 | _cleanup_(sd_event_unrefp) sd_event *event = NULL; |
163 | _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; | |
164 | _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; | |
86f210e9 MP |
165 | char *ifname; |
166 | ||
167 | ifname = strdup("lo2"); | |
168 | assert_se(ifname); | |
169 | ||
170 | assert_se(sd_netlink_open(&rtnl) >= 0); | |
171 | assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_GETLINK, ifindex) >= 0); | |
172 | ||
6e866b33 | 173 | assert_se(sd_netlink_call_async(rtnl, NULL, m, link_handler, NULL, ifname, 0, NULL) >= 0); |
86f210e9 MP |
174 | |
175 | assert_se(sd_event_default(&event) >= 0); | |
176 | ||
177 | assert_se(sd_netlink_attach_event(rtnl, event, 0) >= 0); | |
178 | ||
179 | assert_se(sd_event_run(event, 0) >= 0); | |
180 | ||
181 | assert_se(sd_netlink_detach_event(rtnl) >= 0); | |
182 | ||
183 | assert_se((rtnl = sd_netlink_unref(rtnl)) == NULL); | |
184 | } | |
185 | ||
6e866b33 MB |
186 | static void test_async_destroy(void *userdata) { |
187 | } | |
86f210e9 | 188 | |
6e866b33 MB |
189 | static void test_async(int ifindex) { |
190 | _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; | |
191 | _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL, *r = NULL; | |
192 | _cleanup_(sd_netlink_slot_unrefp) sd_netlink_slot *slot = NULL; | |
193 | sd_netlink_destroy_t destroy_callback; | |
194 | const char *description; | |
195 | char *ifname; | |
86f210e9 | 196 | |
6e866b33 MB |
197 | ifname = strdup("lo"); |
198 | assert_se(ifname); | |
86f210e9 | 199 | |
6e866b33 | 200 | assert_se(sd_netlink_open(&rtnl) >= 0); |
86f210e9 | 201 | |
6e866b33 | 202 | assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_GETLINK, ifindex) >= 0); |
86f210e9 | 203 | |
6e866b33 MB |
204 | assert_se(sd_netlink_call_async(rtnl, &slot, m, link_handler, test_async_destroy, ifname, 0, "hogehoge") >= 0); |
205 | ||
206 | assert_se(sd_netlink_slot_get_netlink(slot) == rtnl); | |
207 | assert_se(sd_netlink_slot_get_userdata(slot) == ifname); | |
208 | assert_se(sd_netlink_slot_get_destroy_callback(slot, &destroy_callback) == 1); | |
209 | assert_se(destroy_callback == test_async_destroy); | |
210 | assert_se(sd_netlink_slot_get_floating(slot) == 0); | |
211 | assert_se(sd_netlink_slot_get_description(slot, &description) == 1); | |
212 | assert_se(streq(description, "hogehoge")); | |
213 | ||
214 | assert_se(sd_netlink_wait(rtnl, 0) >= 0); | |
215 | assert_se(sd_netlink_process(rtnl, &r) >= 0); | |
216 | ||
217 | assert_se((rtnl = sd_netlink_unref(rtnl)) == NULL); | |
86f210e9 MP |
218 | } |
219 | ||
6e866b33 | 220 | static void test_slot_set(int ifindex) { |
4c89c718 MP |
221 | _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; |
222 | _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL, *r = NULL; | |
6e866b33 MB |
223 | _cleanup_(sd_netlink_slot_unrefp) sd_netlink_slot *slot = NULL; |
224 | sd_netlink_destroy_t destroy_callback; | |
225 | const char *description; | |
86f210e9 MP |
226 | char *ifname; |
227 | ||
228 | ifname = strdup("lo"); | |
229 | assert_se(ifname); | |
230 | ||
231 | assert_se(sd_netlink_open(&rtnl) >= 0); | |
232 | ||
233 | assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_GETLINK, ifindex) >= 0); | |
234 | ||
6e866b33 MB |
235 | assert_se(sd_netlink_call_async(rtnl, &slot, m, link_handler, NULL, NULL, 0, NULL) >= 0); |
236 | ||
237 | assert_se(sd_netlink_slot_get_netlink(slot) == rtnl); | |
238 | assert_se(!sd_netlink_slot_get_userdata(slot)); | |
239 | assert_se(!sd_netlink_slot_set_userdata(slot, ifname)); | |
240 | assert_se(sd_netlink_slot_get_userdata(slot) == ifname); | |
241 | assert_se(sd_netlink_slot_get_destroy_callback(slot, NULL) == 0); | |
242 | assert_se(sd_netlink_slot_set_destroy_callback(slot, test_async_destroy) >= 0); | |
243 | assert_se(sd_netlink_slot_get_destroy_callback(slot, &destroy_callback) == 1); | |
244 | assert_se(destroy_callback == test_async_destroy); | |
245 | assert_se(sd_netlink_slot_get_floating(slot) == 0); | |
246 | assert_se(sd_netlink_slot_set_floating(slot, 1) == 1); | |
247 | assert_se(sd_netlink_slot_get_floating(slot) == 1); | |
248 | assert_se(sd_netlink_slot_get_description(slot, NULL) == 0); | |
249 | assert_se(sd_netlink_slot_set_description(slot, "hogehoge") >= 0); | |
250 | assert_se(sd_netlink_slot_get_description(slot, &description) == 1); | |
251 | assert_se(streq(description, "hogehoge")); | |
86f210e9 MP |
252 | |
253 | assert_se(sd_netlink_wait(rtnl, 0) >= 0); | |
254 | assert_se(sd_netlink_process(rtnl, &r) >= 0); | |
255 | ||
256 | assert_se((rtnl = sd_netlink_unref(rtnl)) == NULL); | |
257 | } | |
258 | ||
6e866b33 MB |
259 | struct test_async_object { |
260 | unsigned n_ref; | |
261 | char *ifname; | |
262 | }; | |
263 | ||
264 | static struct test_async_object *test_async_object_free(struct test_async_object *t) { | |
265 | assert(t); | |
266 | ||
267 | free(t->ifname); | |
268 | return mfree(t); | |
269 | } | |
270 | ||
271 | DEFINE_PRIVATE_TRIVIAL_REF_UNREF_FUNC(struct test_async_object, test_async_object, test_async_object_free); | |
272 | DEFINE_TRIVIAL_CLEANUP_FUNC(struct test_async_object *, test_async_object_unref); | |
273 | ||
274 | static int link_handler2(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) { | |
275 | struct test_async_object *t = userdata; | |
276 | const char *data; | |
277 | ||
278 | assert_se(rtnl); | |
279 | assert_se(m); | |
280 | assert_se(userdata); | |
281 | ||
282 | log_info("%s: got link info about %s", __func__, t->ifname); | |
283 | ||
284 | assert_se(sd_netlink_message_read_string(m, IFLA_IFNAME, &data) >= 0); | |
285 | assert_se(streq(data, "lo")); | |
286 | ||
287 | return 1; | |
288 | } | |
289 | ||
290 | static void test_async_object_destroy(void *userdata) { | |
291 | struct test_async_object *t = userdata; | |
292 | ||
293 | assert(userdata); | |
294 | ||
295 | log_info("%s: n_ref=%u", __func__, t->n_ref); | |
296 | test_async_object_unref(t); | |
297 | } | |
298 | ||
299 | static void test_async_destroy_callback(int ifindex) { | |
300 | _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; | |
301 | _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL, *r = NULL; | |
302 | _cleanup_(test_async_object_unrefp) struct test_async_object *t = NULL; | |
303 | _cleanup_(sd_netlink_slot_unrefp) sd_netlink_slot *slot = NULL; | |
304 | char *ifname; | |
305 | ||
306 | assert_se(t = new(struct test_async_object, 1)); | |
307 | assert_se(ifname = strdup("lo")); | |
308 | *t = (struct test_async_object) { | |
309 | .n_ref = 1, | |
310 | .ifname = ifname, | |
311 | }; | |
312 | ||
313 | assert_se(sd_netlink_open(&rtnl) >= 0); | |
314 | ||
315 | /* destroy callback is called after processing message */ | |
316 | assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_GETLINK, ifindex) >= 0); | |
317 | assert_se(sd_netlink_call_async(rtnl, NULL, m, link_handler2, test_async_object_destroy, t, 0, NULL) >= 0); | |
318 | ||
319 | assert_se(t->n_ref == 1); | |
320 | assert_se(test_async_object_ref(t)); | |
321 | assert_se(t->n_ref == 2); | |
322 | ||
323 | assert_se(sd_netlink_wait(rtnl, 0) >= 0); | |
324 | assert_se(sd_netlink_process(rtnl, &r) == 1); | |
325 | assert_se(t->n_ref == 1); | |
326 | ||
327 | assert_se(!sd_netlink_message_unref(m)); | |
328 | ||
329 | /* destroy callback is called when asynchronous call is cancelled, that is, slot is freed. */ | |
330 | assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_GETLINK, ifindex) >= 0); | |
331 | assert_se(sd_netlink_call_async(rtnl, &slot, m, link_handler2, test_async_object_destroy, t, 0, NULL) >= 0); | |
332 | ||
333 | assert_se(t->n_ref == 1); | |
334 | assert_se(test_async_object_ref(t)); | |
335 | assert_se(t->n_ref == 2); | |
336 | ||
337 | assert_se(!(slot = sd_netlink_slot_unref(slot))); | |
338 | assert_se(t->n_ref == 1); | |
339 | ||
340 | assert_se(!sd_netlink_message_unref(m)); | |
341 | ||
342 | /* destroy callback is also called by sd_netlink_unref() */ | |
343 | assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_GETLINK, ifindex) >= 0); | |
344 | assert_se(sd_netlink_call_async(rtnl, NULL, m, link_handler2, test_async_object_destroy, t, 0, NULL) >= 0); | |
345 | ||
346 | assert_se(t->n_ref == 1); | |
347 | assert_se(test_async_object_ref(t)); | |
348 | assert_se(t->n_ref == 2); | |
349 | ||
350 | assert_se((rtnl = sd_netlink_unref(rtnl)) == NULL); | |
351 | assert_se(t->n_ref == 1); | |
352 | } | |
353 | ||
354 | static int pipe_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) { | |
355 | int *counter = userdata; | |
356 | int r; | |
357 | ||
358 | (*counter)--; | |
359 | ||
360 | r = sd_netlink_message_get_errno(m); | |
361 | ||
362 | log_info_errno(r, "%d left in pipe. got reply: %m", *counter); | |
363 | ||
364 | assert_se(r >= 0); | |
365 | ||
366 | return 1; | |
367 | } | |
368 | ||
86f210e9 | 369 | static void test_pipe(int ifindex) { |
4c89c718 MP |
370 | _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; |
371 | _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m1 = NULL, *m2 = NULL; | |
86f210e9 MP |
372 | int counter = 0; |
373 | ||
374 | assert_se(sd_netlink_open(&rtnl) >= 0); | |
375 | ||
376 | assert_se(sd_rtnl_message_new_link(rtnl, &m1, RTM_GETLINK, ifindex) >= 0); | |
377 | assert_se(sd_rtnl_message_new_link(rtnl, &m2, RTM_GETLINK, ifindex) >= 0); | |
378 | ||
aa27b158 | 379 | counter++; |
6e866b33 | 380 | assert_se(sd_netlink_call_async(rtnl, NULL, m1, pipe_handler, NULL, &counter, 0, NULL) >= 0); |
86f210e9 | 381 | |
aa27b158 | 382 | counter++; |
6e866b33 | 383 | assert_se(sd_netlink_call_async(rtnl, NULL, m2, pipe_handler, NULL, &counter, 0, NULL) >= 0); |
86f210e9 MP |
384 | |
385 | while (counter > 0) { | |
386 | assert_se(sd_netlink_wait(rtnl, 0) >= 0); | |
387 | assert_se(sd_netlink_process(rtnl, NULL) >= 0); | |
388 | } | |
389 | ||
390 | assert_se((rtnl = sd_netlink_unref(rtnl)) == NULL); | |
391 | } | |
392 | ||
1d42b86d | 393 | static void test_container(sd_netlink *rtnl) { |
4c89c718 | 394 | _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; |
86f210e9 MP |
395 | uint16_t u16_data; |
396 | uint32_t u32_data; | |
397 | const char *string_data; | |
398 | ||
1d42b86d | 399 | assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_NEWLINK, 0) >= 0); |
86f210e9 MP |
400 | |
401 | assert_se(sd_netlink_message_open_container(m, IFLA_LINKINFO) >= 0); | |
402 | assert_se(sd_netlink_message_open_container_union(m, IFLA_INFO_DATA, "vlan") >= 0); | |
403 | assert_se(sd_netlink_message_append_u16(m, IFLA_VLAN_ID, 100) >= 0); | |
404 | assert_se(sd_netlink_message_close_container(m) >= 0); | |
405 | assert_se(sd_netlink_message_append_string(m, IFLA_INFO_KIND, "vlan") >= 0); | |
406 | assert_se(sd_netlink_message_close_container(m) >= 0); | |
407 | assert_se(sd_netlink_message_close_container(m) == -EINVAL); | |
408 | ||
e1f67bc7 | 409 | assert_se(sd_netlink_message_rewind(m, NULL) >= 0); |
86f210e9 MP |
410 | |
411 | assert_se(sd_netlink_message_enter_container(m, IFLA_LINKINFO) >= 0); | |
412 | assert_se(sd_netlink_message_read_string(m, IFLA_INFO_KIND, &string_data) >= 0); | |
413 | assert_se(streq("vlan", string_data)); | |
414 | ||
415 | assert_se(sd_netlink_message_enter_container(m, IFLA_INFO_DATA) >= 0); | |
416 | assert_se(sd_netlink_message_read_u16(m, IFLA_VLAN_ID, &u16_data) >= 0); | |
417 | assert_se(sd_netlink_message_exit_container(m) >= 0); | |
418 | ||
419 | assert_se(sd_netlink_message_read_string(m, IFLA_INFO_KIND, &string_data) >= 0); | |
420 | assert_se(streq("vlan", string_data)); | |
421 | assert_se(sd_netlink_message_exit_container(m) >= 0); | |
422 | ||
423 | assert_se(sd_netlink_message_read_u32(m, IFLA_LINKINFO, &u32_data) < 0); | |
424 | ||
425 | assert_se(sd_netlink_message_exit_container(m) == -EINVAL); | |
426 | } | |
427 | ||
428 | static void test_match(void) { | |
6e866b33 | 429 | _cleanup_(sd_netlink_slot_unrefp) sd_netlink_slot *s1 = NULL, *s2 = NULL; |
4c89c718 | 430 | _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; |
86f210e9 MP |
431 | |
432 | assert_se(sd_netlink_open(&rtnl) >= 0); | |
433 | ||
6e866b33 MB |
434 | assert_se(sd_netlink_add_match(rtnl, &s1, RTM_NEWLINK, link_handler, NULL, NULL, NULL) >= 0); |
435 | assert_se(sd_netlink_add_match(rtnl, &s2, RTM_NEWLINK, link_handler, NULL, NULL, NULL) >= 0); | |
436 | assert_se(sd_netlink_add_match(rtnl, NULL, RTM_NEWLINK, link_handler, NULL, NULL, NULL) >= 0); | |
86f210e9 | 437 | |
6e866b33 MB |
438 | assert_se(!(s1 = sd_netlink_slot_unref(s1))); |
439 | assert_se(!(s2 = sd_netlink_slot_unref(s2))); | |
86f210e9 MP |
440 | |
441 | assert_se((rtnl = sd_netlink_unref(rtnl)) == NULL); | |
442 | } | |
443 | ||
444 | static void test_get_addresses(sd_netlink *rtnl) { | |
4c89c718 | 445 | _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL; |
86f210e9 MP |
446 | sd_netlink_message *m; |
447 | ||
448 | assert_se(sd_rtnl_message_new_addr(rtnl, &req, RTM_GETADDR, 0, AF_UNSPEC) >= 0); | |
8b3d4ff0 | 449 | assert_se(sd_netlink_message_request_dump(req, true) >= 0); |
86f210e9 MP |
450 | assert_se(sd_netlink_call(rtnl, req, 0, &reply) >= 0); |
451 | ||
452 | for (m = reply; m; m = sd_netlink_message_next(m)) { | |
453 | uint16_t type; | |
454 | unsigned char scope, flags; | |
455 | int family, ifindex; | |
456 | ||
457 | assert_se(sd_netlink_message_get_type(m, &type) >= 0); | |
458 | assert_se(type == RTM_NEWADDR); | |
459 | ||
460 | assert_se(sd_rtnl_message_addr_get_ifindex(m, &ifindex) >= 0); | |
461 | assert_se(sd_rtnl_message_addr_get_family(m, &family) >= 0); | |
462 | assert_se(sd_rtnl_message_addr_get_scope(m, &scope) >= 0); | |
463 | assert_se(sd_rtnl_message_addr_get_flags(m, &flags) >= 0); | |
464 | ||
465 | assert_se(ifindex > 0); | |
f5e65279 | 466 | assert_se(IN_SET(family, AF_INET, AF_INET6)); |
86f210e9 MP |
467 | |
468 | log_info("got IPv%u address on ifindex %i", family == AF_INET ? 4: 6, ifindex); | |
469 | } | |
470 | } | |
471 | ||
1d42b86d | 472 | static void test_message(sd_netlink *rtnl) { |
4c89c718 | 473 | _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; |
86f210e9 | 474 | |
1d42b86d | 475 | assert_se(rtnl_message_new_synthetic_error(rtnl, -ETIMEDOUT, 1, &m) >= 0); |
86f210e9 MP |
476 | assert_se(sd_netlink_message_get_errno(m) == -ETIMEDOUT); |
477 | } | |
478 | ||
f2dec872 BR |
479 | static void test_array(void) { |
480 | _cleanup_(sd_netlink_unrefp) sd_netlink *genl = NULL; | |
481 | _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; | |
482 | ||
483 | assert_se(sd_genl_socket_open(&genl) >= 0); | |
484 | assert_se(sd_genl_message_new(genl, SD_GENL_ID_CTRL, CTRL_CMD_GETFAMILY, &m) >= 0); | |
485 | ||
486 | assert_se(sd_netlink_message_open_container(m, CTRL_ATTR_MCAST_GROUPS) >= 0); | |
487 | for (unsigned i = 0; i < 10; i++) { | |
488 | char name[STRLEN("hoge") + DECIMAL_STR_MAX(uint32_t)]; | |
489 | uint32_t id = i + 1000; | |
490 | ||
491 | xsprintf(name, "hoge%" PRIu32, id); | |
492 | assert_se(sd_netlink_message_open_array(m, i + 1) >= 0); | |
493 | assert_se(sd_netlink_message_append_u32(m, CTRL_ATTR_MCAST_GRP_ID, id) >= 0); | |
494 | assert_se(sd_netlink_message_append_string(m, CTRL_ATTR_MCAST_GRP_NAME, name) >= 0); | |
495 | assert_se(sd_netlink_message_close_container(m) >= 0); | |
496 | } | |
497 | assert_se(sd_netlink_message_close_container(m) >= 0); | |
498 | ||
499 | rtnl_message_seal(m); | |
e1f67bc7 | 500 | assert_se(sd_netlink_message_rewind(m, genl) >= 0); |
f2dec872 BR |
501 | |
502 | assert_se(sd_netlink_message_enter_container(m, CTRL_ATTR_MCAST_GROUPS) >= 0); | |
503 | for (unsigned i = 0; i < 10; i++) { | |
504 | char expected[STRLEN("hoge") + DECIMAL_STR_MAX(uint32_t)]; | |
505 | const char *name; | |
506 | uint32_t id; | |
507 | ||
508 | assert_se(sd_netlink_message_enter_array(m, i + 1) >= 0); | |
509 | assert_se(sd_netlink_message_read_u32(m, CTRL_ATTR_MCAST_GRP_ID, &id) >= 0); | |
510 | assert_se(sd_netlink_message_read_string(m, CTRL_ATTR_MCAST_GRP_NAME, &name) >= 0); | |
511 | assert_se(sd_netlink_message_exit_container(m) >= 0); | |
512 | ||
513 | assert_se(id == i + 1000); | |
514 | xsprintf(expected, "hoge%" PRIu32, id); | |
515 | assert_se(streq(name, expected)); | |
516 | } | |
517 | assert_se(sd_netlink_message_exit_container(m) >= 0); | |
46cdbd49 BR |
518 | } |
519 | ||
520 | static void test_strv(sd_netlink *rtnl) { | |
521 | _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; | |
522 | _cleanup_strv_free_ char **names_in = NULL, **names_out; | |
523 | const char *p; | |
524 | ||
525 | assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_NEWLINKPROP, 1) >= 0); | |
526 | ||
527 | for (unsigned i = 0; i < 10; i++) { | |
528 | char name[STRLEN("hoge") + DECIMAL_STR_MAX(uint32_t)]; | |
529 | ||
530 | xsprintf(name, "hoge%" PRIu32, i + 1000); | |
531 | assert_se(strv_extend(&names_in, name) >= 0); | |
532 | } | |
533 | ||
534 | assert_se(sd_netlink_message_open_container(m, IFLA_PROP_LIST) >= 0); | |
535 | assert_se(sd_netlink_message_append_strv(m, IFLA_ALT_IFNAME, names_in) >= 0); | |
536 | assert_se(sd_netlink_message_close_container(m) >= 0); | |
537 | ||
538 | rtnl_message_seal(m); | |
539 | assert_se(sd_netlink_message_rewind(m, NULL) >= 0); | |
f2dec872 | 540 | |
46cdbd49 BR |
541 | assert_se(sd_netlink_message_read_strv(m, IFLA_PROP_LIST, IFLA_ALT_IFNAME, &names_out) >= 0); |
542 | assert_se(strv_equal(names_in, names_out)); | |
543 | ||
544 | assert_se(sd_netlink_message_enter_container(m, IFLA_PROP_LIST) >= 0); | |
545 | assert_se(sd_netlink_message_read_string(m, IFLA_ALT_IFNAME, &p) >= 0); | |
546 | assert_se(streq(p, "hoge1009")); | |
547 | assert_se(sd_netlink_message_exit_container(m) >= 0); | |
f2dec872 BR |
548 | } |
549 | ||
86f210e9 MP |
550 | int main(void) { |
551 | sd_netlink *rtnl; | |
552 | sd_netlink_message *m; | |
553 | sd_netlink_message *r; | |
554 | const char *string_data; | |
555 | int if_loopback; | |
556 | uint16_t type; | |
557 | ||
86f210e9 | 558 | test_match(); |
86f210e9 MP |
559 | test_multiple(); |
560 | ||
86f210e9 MP |
561 | assert_se(sd_netlink_open(&rtnl) >= 0); |
562 | assert_se(rtnl); | |
563 | ||
1d42b86d | 564 | test_route(rtnl); |
1d42b86d | 565 | test_message(rtnl); |
1d42b86d | 566 | test_container(rtnl); |
f2dec872 | 567 | test_array(); |
46cdbd49 | 568 | test_strv(rtnl); |
1d42b86d | 569 | |
86f210e9 MP |
570 | if_loopback = (int) if_nametoindex("lo"); |
571 | assert_se(if_loopback > 0); | |
572 | ||
573 | test_async(if_loopback); | |
6e866b33 MB |
574 | test_slot_set(if_loopback); |
575 | test_async_destroy_callback(if_loopback); | |
86f210e9 | 576 | test_pipe(if_loopback); |
86f210e9 | 577 | test_event_loop(if_loopback); |
86f210e9 MP |
578 | test_link_configure(rtnl, if_loopback); |
579 | ||
580 | test_get_addresses(rtnl); | |
86f210e9 MP |
581 | test_message_link_bridge(rtnl); |
582 | ||
583 | assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_GETLINK, if_loopback) >= 0); | |
584 | assert_se(m); | |
585 | ||
586 | assert_se(sd_netlink_message_get_type(m, &type) >= 0); | |
587 | assert_se(type == RTM_GETLINK); | |
588 | ||
589 | assert_se(sd_netlink_message_read_string(m, IFLA_IFNAME, &string_data) == -EPERM); | |
590 | ||
591 | assert_se(sd_netlink_call(rtnl, m, 0, &r) == 1); | |
592 | assert_se(sd_netlink_message_get_type(r, &type) >= 0); | |
593 | assert_se(type == RTM_NEWLINK); | |
594 | ||
595 | assert_se((r = sd_netlink_message_unref(r)) == NULL); | |
596 | ||
597 | assert_se(sd_netlink_call(rtnl, m, -1, &r) == -EPERM); | |
598 | assert_se((m = sd_netlink_message_unref(m)) == NULL); | |
599 | assert_se((r = sd_netlink_message_unref(r)) == NULL); | |
600 | ||
601 | test_link_get(rtnl, if_loopback); | |
602 | test_address_get(rtnl, if_loopback); | |
603 | ||
604 | assert_se((m = sd_netlink_message_unref(m)) == NULL); | |
605 | assert_se((r = sd_netlink_message_unref(r)) == NULL); | |
606 | assert_se((rtnl = sd_netlink_unref(rtnl)) == NULL); | |
607 | ||
608 | return EXIT_SUCCESS; | |
609 | } |