]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd-network/test-ndisc-rs.c
test: drop timeout handlers
[thirdparty/systemd.git] / src / libsystemd-network / test-ndisc-rs.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
f20a35cc 2/***
810adae9 3 Copyright © 2014 Intel Corporation. All rights reserved.
f20a35cc
PF
4***/
5
6#include <netinet/icmp6.h>
1e7a0e21 7#include <arpa/inet.h>
ca78ad1d 8#include <unistd.h>
f20a35cc 9
07630cea 10#include "sd-ndisc.h"
f20a35cc 11
1e7a0e21
LP
12#include "alloc-util.h"
13#include "hexdecoct.h"
940367a0 14#include "icmp6-util.h"
07630cea 15#include "socket-util.h"
1e7a0e21 16#include "strv.h"
5a67ed24 17#include "ndisc-internal.h"
6d7c4033 18#include "tests.h"
f20a35cc
PF
19
20static struct ether_addr mac_addr = {
21 .ether_addr_octet = {'A', 'B', 'C', '1', '2', '3'}
22};
23
24static bool verbose = false;
f20a35cc 25static int test_fd[2];
5a67ed24 26static sd_ndisc *test_timeout_nd;
f20a35cc 27
99af546d
PF
28typedef int (*send_ra_t)(uint8_t flags);
29static send_ra_t send_ra_function;
30
1e7a0e21
LP
31static void router_dump(sd_ndisc_router *rt) {
32 struct in6_addr addr;
1e7a0e21
LP
33 uint8_t hop_limit;
34 uint64_t t, flags;
35 uint32_t mtu;
36 uint16_t lifetime;
37 unsigned preference;
38 int r;
39
40 assert_se(rt);
41
42 log_info("--");
43 assert_se(sd_ndisc_router_get_address(rt, &addr) == -ENODATA);
44
45 assert_se(sd_ndisc_router_get_timestamp(rt, CLOCK_REALTIME, &t) >= 0);
04f5c018 46 log_info("Timestamp: %s", FORMAT_TIMESTAMP(t));
1e7a0e21
LP
47
48 assert_se(sd_ndisc_router_get_timestamp(rt, CLOCK_MONOTONIC, &t) >= 0);
49 log_info("Monotonic: %" PRIu64, t);
50
51 if (sd_ndisc_router_get_hop_limit(rt, &hop_limit) < 0)
52 log_info("No hop limit set");
53 else
54 log_info("Hop limit: %u", hop_limit);
55
56 assert_se(sd_ndisc_router_get_flags(rt, &flags) >= 0);
57 log_info("Flags: <%s|%s>",
58 flags & ND_RA_FLAG_OTHER ? "OTHER" : "",
59 flags & ND_RA_FLAG_MANAGED ? "MANAGED" : "");
60
61 assert_se(sd_ndisc_router_get_preference(rt, &preference) >= 0);
62 log_info("Preference: %s",
63 preference == SD_NDISC_PREFERENCE_LOW ? "low" :
64 preference == SD_NDISC_PREFERENCE_HIGH ? "high" : "medium");
65
66 assert_se(sd_ndisc_router_get_lifetime(rt, &lifetime) >= 0);
67 log_info("Lifetime: %" PRIu16, lifetime);
68
69 if (sd_ndisc_router_get_mtu(rt, &mtu) < 0)
70 log_info("No MTU set");
71 else
72 log_info("MTU: %" PRIu32, mtu);
73
74 r = sd_ndisc_router_option_rewind(rt);
75 for (;;) {
76 uint8_t type;
77
78 assert_se(r >= 0);
79
80 if (r == 0)
81 break;
82
83 assert_se(sd_ndisc_router_option_get_type(rt, &type) >= 0);
84
85 log_info(">> Option %u", type);
86
87 switch (type) {
88
89 case SD_NDISC_OPTION_SOURCE_LL_ADDRESS:
90 case SD_NDISC_OPTION_TARGET_LL_ADDRESS: {
91 _cleanup_free_ char *c = NULL;
92 const void *p;
93 size_t n;
94
95 assert_se(sd_ndisc_router_option_get_raw(rt, &p, &n) >= 0);
96 assert_se(n > 2);
97 assert_se(c = hexmem((uint8_t*) p + 2, n - 2));
98
99 log_info("Address: %s", c);
100 break;
101 }
102
103 case SD_NDISC_OPTION_PREFIX_INFORMATION: {
104 uint32_t lifetime_valid, lifetime_preferred;
105 unsigned prefix_len;
106 uint8_t pfl;
107 struct in6_addr a;
108 char buff[INET6_ADDRSTRLEN];
109
110 assert_se(sd_ndisc_router_prefix_get_valid_lifetime(rt, &lifetime_valid) >= 0);
111 log_info("Valid Lifetime: %" PRIu32, lifetime_valid);
112
113 assert_se(sd_ndisc_router_prefix_get_preferred_lifetime(rt, &lifetime_preferred) >= 0);
114 log_info("Preferred Lifetime: %" PRIu32, lifetime_preferred);
115
116 assert_se(sd_ndisc_router_prefix_get_flags(rt, &pfl) >= 0);
117 log_info("Flags: <%s|%s>",
118 pfl & ND_OPT_PI_FLAG_ONLINK ? "ONLINK" : "",
119 pfl & ND_OPT_PI_FLAG_AUTO ? "AUTO" : "");
120
121 assert_se(sd_ndisc_router_prefix_get_prefixlen(rt, &prefix_len) >= 0);
122 log_info("Prefix Length: %u", prefix_len);
123
124 assert_se(sd_ndisc_router_prefix_get_address(rt, &a) >= 0);
125 log_info("Prefix: %s", inet_ntop(AF_INET6, &a, buff, sizeof(buff)));
126
127 break;
128 }
129
130 case SD_NDISC_OPTION_RDNSS: {
131 const struct in6_addr *a;
132 uint32_t lt;
133 int n, i;
134
135 n = sd_ndisc_router_rdnss_get_addresses(rt, &a);
136 assert_se(n > 0);
137
138 for (i = 0; i < n; i++) {
139 char buff[INET6_ADDRSTRLEN];
140 log_info("DNS: %s", inet_ntop(AF_INET6, a + i, buff, sizeof(buff)));
141 }
142
143 assert_se(sd_ndisc_router_rdnss_get_lifetime(rt, &lt) >= 0);
144 log_info("Lifetime: %" PRIu32, lt);
145 break;
146 }
147
148 case SD_NDISC_OPTION_DNSSL: {
149 _cleanup_strv_free_ char **l = NULL;
150 uint32_t lt;
151 int n, i;
152
153 n = sd_ndisc_router_dnssl_get_domains(rt, &l);
154 assert_se(n > 0);
155
156 for (i = 0; i < n; i++)
157 log_info("Domain: %s", l[i]);
158
159 assert_se(sd_ndisc_router_dnssl_get_lifetime(rt, &lt) >= 0);
160 log_info("Lifetime: %" PRIu32, lt);
161 break;
162 }}
163
164 r = sd_ndisc_router_option_next(rt);
165 }
166}
167
1a6c9136
YW
168int icmp6_bind_router_solicitation(int ifindex) {
169 assert_se(ifindex == 42);
f20a35cc 170
3e29b889 171 if (socketpair(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0, test_fd) < 0)
f20a35cc
PF
172 return -errno;
173
174 return test_fd[0];
175}
176
1a6c9136 177int icmp6_bind_router_advertisement(int ifindex) {
6142bb37
PF
178 return -ENOSYS;
179}
180
88d5a3db
PF
181int icmp6_receive(int fd, void *iov_base, size_t iov_len,
182 struct in6_addr *dst, triple_timestamp *timestamp) {
19500112 183 assert_se(read (fd, iov_base, iov_len) == (ssize_t)iov_len);
88d5a3db
PF
184
185 if (timestamp)
186 triple_timestamp_get(timestamp);
187
188 return 0;
189}
190
f20a35cc
PF
191static int send_ra(uint8_t flags) {
192 uint8_t advertisement[] = {
193 0x86, 0x00, 0xde, 0x83, 0x40, 0xc0, 0x00, 0xb4,
194 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
195 0x03, 0x04, 0x40, 0xc0, 0x00, 0x00, 0x01, 0xf4,
196 0x00, 0x00, 0x01, 0xb8, 0x00, 0x00, 0x00, 0x00,
197 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
198 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
199 0x19, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
200 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
201 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
202 0x1f, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
203 0x03, 0x6c, 0x61, 0x62, 0x05, 0x69, 0x6e, 0x74,
204 0x72, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
205 0x01, 0x01, 0x78, 0x2b, 0xcb, 0xb3, 0x6d, 0x53,
206 };
207
208 advertisement[5] = flags;
209
787784c4 210 assert_se(write(test_fd[1], advertisement, sizeof(advertisement)) ==
c21ed681 211 sizeof(advertisement));
f20a35cc
PF
212
213 if (verbose)
214 printf(" sent RA with flag 0x%02x\n", flags);
215
216 return 0;
217}
218
940367a0 219int icmp6_send_router_solicitation(int s, const struct ether_addr *ether_addr) {
5a67ed24
PF
220 if (!send_ra_function)
221 return 0;
222
99af546d 223 return send_ra_function(0);
f20a35cc
PF
224}
225
2324fd3a 226static void test_callback(sd_ndisc *nd, sd_ndisc_event_t event, sd_ndisc_router *rt, void *userdata) {
f20a35cc 227 sd_event *e = userdata;
cb53894d 228 static unsigned idx = 0;
1e7a0e21 229 uint64_t flags_array[] = {
9d96e6c3
TG
230 0,
231 0,
232 0,
233 ND_RA_FLAG_OTHER,
234 ND_RA_FLAG_MANAGED
f20a35cc 235 };
1e7a0e21 236 uint64_t flags;
8d7f2c6a 237
787784c4 238 assert_se(nd);
f20a35cc 239
1e7a0e21
LP
240 if (event != SD_NDISC_EVENT_ROUTER)
241 return;
242
243 router_dump(rt);
244
245 assert_se(sd_ndisc_router_get_flags(rt, &flags) >= 0);
9d96e6c3 246 assert_se(flags == flags_array[idx]);
f20a35cc
PF
247 idx++;
248
249 if (verbose)
1e7a0e21 250 printf(" got event 0x%02" PRIx64 "\n", flags);
f20a35cc 251
9d96e6c3
TG
252 if (idx < ELEMENTSOF(flags_array)) {
253 send_ra(flags_array[idx]);
8d7f2c6a
PF
254 return;
255 }
256
8d7f2c6a 257 sd_event_exit(e, 0);
f20a35cc
PF
258}
259
99af546d
PF
260static void test_rs(void) {
261 sd_event *e;
4d7b83da 262 sd_ndisc *nd;
f20a35cc
PF
263
264 if (verbose)
7fbae5b7 265 printf("* %s\n", __func__);
f20a35cc 266
99af546d
PF
267 send_ra_function = send_ra;
268
269 assert_se(sd_event_new(&e) >= 0);
270
4d7b83da 271 assert_se(sd_ndisc_new(&nd) >= 0);
787784c4 272 assert_se(nd);
f20a35cc 273
4d7b83da 274 assert_se(sd_ndisc_attach_event(nd, e, 0) >= 0);
f20a35cc 275
2f8e7633 276 assert_se(sd_ndisc_set_ifindex(nd, 42) >= 0);
4d7b83da 277 assert_se(sd_ndisc_set_mac(nd, &mac_addr) >= 0);
1e7a0e21 278 assert_se(sd_ndisc_set_callback(nd, test_callback, e) >= 0);
f20a35cc 279
2e37084f
YW
280 assert_se(sd_event_add_time_relative(e, NULL, clock_boottime_or_monotonic(),
281 30 * USEC_PER_SEC, 0,
282 NULL, INT_TO_PTR(-ETIMEDOUT)) >= 0);
f20a35cc 283
4d7b83da 284 assert_se(sd_ndisc_stop(nd) >= 0);
1e7a0e21 285 assert_se(sd_ndisc_start(nd) >= 0);
6b8a1aa6 286 assert_se(sd_ndisc_start(nd) >= 0);
4d7b83da 287 assert_se(sd_ndisc_stop(nd) >= 0);
836cf090 288
1e7a0e21 289 assert_se(sd_ndisc_start(nd) >= 0);
f20a35cc 290
2e37084f 291 assert_se(sd_event_loop(e) >= 0);
f20a35cc 292
4d7b83da 293 nd = sd_ndisc_unref(nd);
787784c4 294 assert_se(!nd);
f20a35cc 295
f20a35cc 296 close(test_fd[1]);
99af546d
PF
297
298 sd_event_unref(e);
f20a35cc
PF
299}
300
5a67ed24
PF
301static int test_timeout_value(uint8_t flags) {
302 static int count = 0;
303 static usec_t last = 0;
304 sd_ndisc *nd = test_timeout_nd;
305 usec_t min, max;
5a67ed24
PF
306
307 assert_se(nd);
308 assert_se(nd->event);
309
310 if (++count >= 20)
311 sd_event_exit(nd->event, 0);
312
313 if (last == 0) {
314 /* initial RT = IRT + RAND*IRT */
315 min = NDISC_ROUTER_SOLICITATION_INTERVAL -
316 NDISC_ROUTER_SOLICITATION_INTERVAL / 10;
317 max = NDISC_ROUTER_SOLICITATION_INTERVAL +
318 NDISC_ROUTER_SOLICITATION_INTERVAL / 10;
319 } else {
320 /* next RT = 2*RTprev + RAND*RTprev */
321 min = 2 * last - last / 10;
322 max = 2 * last + last / 10;
323 }
324
325 /* final RT > MRT */
326 if (last * 2 > NDISC_MAX_ROUTER_SOLICITATION_INTERVAL) {
327 min = NDISC_MAX_ROUTER_SOLICITATION_INTERVAL -
328 NDISC_MAX_ROUTER_SOLICITATION_INTERVAL / 10;
329 max = NDISC_MAX_ROUTER_SOLICITATION_INTERVAL +
330 NDISC_MAX_ROUTER_SOLICITATION_INTERVAL / 10;
331 }
332
5a67ed24
PF
333 log_info("backoff timeout interval %2d %s%s <= %s <= %s",
334 count,
5291f26d
ZJS
335 last * 2 > NDISC_MAX_ROUTER_SOLICITATION_INTERVAL ? "(max) ": "",
336 FORMAT_TIMESPAN(min, USEC_PER_MSEC),
337 FORMAT_TIMESPAN(nd->retransmit_time, USEC_PER_MSEC),
338 FORMAT_TIMESPAN(max, USEC_PER_MSEC));
5a67ed24
PF
339
340 assert_se(min <= nd->retransmit_time);
341 assert_se(max >= nd->retransmit_time);
342
343 last = nd->retransmit_time;
344
345 assert_se(sd_event_source_set_time(nd->timeout_event_source, 0) >= 0);
346
347 return 0;
348}
349
350static void test_timeout(void) {
351 sd_event *e;
352 sd_ndisc *nd;
5a67ed24
PF
353
354 if (verbose)
7fbae5b7 355 printf("* %s\n", __func__);
5a67ed24
PF
356
357 send_ra_function = test_timeout_value;
358
359 assert_se(sd_event_new(&e) >= 0);
360
361 assert_se(sd_ndisc_new(&nd) >= 0);
362 assert_se(nd);
363
364 test_timeout_nd = nd;
365
366 assert_se(sd_ndisc_attach_event(nd, e, 0) >= 0);
367
368 assert_se(sd_ndisc_set_ifindex(nd, 42) >= 0);
369 assert_se(sd_ndisc_set_mac(nd, &mac_addr) >= 0);
370
2e37084f
YW
371 assert_se(sd_event_add_time_relative(e, NULL, clock_boottime_or_monotonic(),
372 30 * USEC_PER_SEC, 0,
373 NULL, INT_TO_PTR(-ETIMEDOUT)) >= 0);
5a67ed24
PF
374
375 assert_se(sd_ndisc_start(nd) >= 0);
376
2e37084f 377 assert_se(sd_event_loop(e) >= 0);
5a67ed24
PF
378
379 nd = sd_ndisc_unref(nd);
380
381 sd_event_unref(e);
382}
383
f20a35cc 384int main(int argc, char *argv[]) {
f20a35cc 385
6d7c4033 386 test_setup_logging(LOG_DEBUG);
f20a35cc 387
99af546d 388 test_rs();
5a67ed24 389 test_timeout();
f20a35cc
PF
390
391 return 0;
392}