]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd-network/test-ndisc-rs.c
Merge pull request #29254 from yuwata/sd-ndisc-use-usec_t
[thirdparty/systemd.git] / src / libsystemd-network / test-ndisc-rs.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2 /***
3 Copyright © 2014 Intel Corporation. All rights reserved.
4 ***/
5
6 #include <netinet/icmp6.h>
7 #include <arpa/inet.h>
8 #include <unistd.h>
9
10 #include "sd-ndisc.h"
11
12 #include "alloc-util.h"
13 #include "fd-util.h"
14 #include "hexdecoct.h"
15 #include "icmp6-util-unix.h"
16 #include "socket-util.h"
17 #include "strv.h"
18 #include "ndisc-internal.h"
19 #include "tests.h"
20
21 static struct ether_addr mac_addr = {
22 .ether_addr_octet = {'A', 'B', 'C', '1', '2', '3'}
23 };
24
25 static bool verbose = false;
26 static sd_ndisc *test_timeout_nd;
27
28 static void router_dump(sd_ndisc_router *rt) {
29 struct in6_addr addr;
30 uint8_t hop_limit;
31 usec_t t, lifetime;
32 uint64_t flags;
33 uint32_t mtu;
34 unsigned preference;
35 int r;
36
37 assert_se(rt);
38
39 log_info("--");
40 assert_se(sd_ndisc_router_get_address(rt, &addr) >= 0);
41 log_info("Sender: %s", IN6_ADDR_TO_STRING(&addr));
42
43 assert_se(sd_ndisc_router_get_timestamp(rt, CLOCK_REALTIME, &t) >= 0);
44 log_info("Timestamp: %s", FORMAT_TIMESTAMP(t));
45
46 assert_se(sd_ndisc_router_get_timestamp(rt, CLOCK_MONOTONIC, &t) >= 0);
47 log_info("Monotonic: %" PRIu64, t);
48
49 if (sd_ndisc_router_get_hop_limit(rt, &hop_limit) < 0)
50 log_info("No hop limit set");
51 else
52 log_info("Hop limit: %u", hop_limit);
53
54 assert_se(sd_ndisc_router_get_flags(rt, &flags) >= 0);
55 log_info("Flags: <%s|%s>",
56 flags & ND_RA_FLAG_OTHER ? "OTHER" : "",
57 flags & ND_RA_FLAG_MANAGED ? "MANAGED" : "");
58
59 assert_se(sd_ndisc_router_get_preference(rt, &preference) >= 0);
60 log_info("Preference: %s",
61 preference == SD_NDISC_PREFERENCE_LOW ? "low" :
62 preference == SD_NDISC_PREFERENCE_HIGH ? "high" : "medium");
63
64 assert_se(sd_ndisc_router_get_lifetime(rt, &lifetime) >= 0);
65 assert_se(sd_ndisc_router_get_lifetime_timestamp(rt, CLOCK_REALTIME, &t) >= 0);
66 log_info("Lifetime: %s (%s)", FORMAT_TIMESPAN(lifetime, USEC_PER_SEC), FORMAT_TIMESTAMP(t));
67
68 if (sd_ndisc_router_get_mtu(rt, &mtu) < 0)
69 log_info("No MTU set");
70 else
71 log_info("MTU: %" PRIu32, mtu);
72
73 r = sd_ndisc_router_option_rewind(rt);
74 for (;;) {
75 uint8_t type;
76
77 assert_se(r >= 0);
78
79 if (r == 0)
80 break;
81
82 assert_se(sd_ndisc_router_option_get_type(rt, &type) >= 0);
83
84 log_info(">> Option %u", type);
85
86 switch (type) {
87
88 case SD_NDISC_OPTION_SOURCE_LL_ADDRESS:
89 case SD_NDISC_OPTION_TARGET_LL_ADDRESS: {
90 _cleanup_free_ char *c = NULL;
91 const void *p;
92 size_t n;
93
94 assert_se(sd_ndisc_router_option_get_raw(rt, &p, &n) >= 0);
95 assert_se(n > 2);
96 assert_se(c = hexmem((uint8_t*) p + 2, n - 2));
97
98 log_info("Address: %s", c);
99 break;
100 }
101
102 case SD_NDISC_OPTION_PREFIX_INFORMATION: {
103 unsigned prefix_len;
104 uint8_t pfl;
105 struct in6_addr a;
106
107 assert_se(sd_ndisc_router_prefix_get_valid_lifetime(rt, &lifetime) >= 0);
108 assert_se(sd_ndisc_router_prefix_get_valid_lifetime_timestamp(rt, CLOCK_REALTIME, &t) >= 0);
109 log_info("Valid Lifetime: %s (%s)", FORMAT_TIMESPAN(lifetime, USEC_PER_SEC), FORMAT_TIMESTAMP(t));
110
111 assert_se(sd_ndisc_router_prefix_get_preferred_lifetime(rt, &lifetime) >= 0);
112 assert_se(sd_ndisc_router_prefix_get_preferred_lifetime_timestamp(rt, CLOCK_REALTIME, &t) >= 0);
113 log_info("Preferred Lifetime: %s (%s)", FORMAT_TIMESPAN(lifetime, USEC_PER_SEC), FORMAT_TIMESTAMP(t));
114
115 assert_se(sd_ndisc_router_prefix_get_flags(rt, &pfl) >= 0);
116 log_info("Flags: <%s|%s>",
117 pfl & ND_OPT_PI_FLAG_ONLINK ? "ONLINK" : "",
118 pfl & ND_OPT_PI_FLAG_AUTO ? "AUTO" : "");
119
120 assert_se(sd_ndisc_router_prefix_get_prefixlen(rt, &prefix_len) >= 0);
121 log_info("Prefix Length: %u", prefix_len);
122
123 assert_se(sd_ndisc_router_prefix_get_address(rt, &a) >= 0);
124 log_info("Prefix: %s", IN6_ADDR_TO_STRING(&a));
125
126 break;
127 }
128
129 case SD_NDISC_OPTION_RDNSS: {
130 const struct in6_addr *a;
131 int n, i;
132
133 n = sd_ndisc_router_rdnss_get_addresses(rt, &a);
134 assert_se(n > 0);
135
136 for (i = 0; i < n; i++)
137 log_info("DNS: %s", IN6_ADDR_TO_STRING(a + i));
138
139 assert_se(sd_ndisc_router_rdnss_get_lifetime(rt, &lifetime) >= 0);
140 assert_se(sd_ndisc_router_rdnss_get_lifetime_timestamp(rt, CLOCK_REALTIME, &t) >= 0);
141 log_info("Lifetime: %s (%s)", FORMAT_TIMESPAN(lifetime, USEC_PER_SEC), FORMAT_TIMESTAMP(t));
142 break;
143 }
144
145 case SD_NDISC_OPTION_DNSSL: {
146 _cleanup_strv_free_ char **l = NULL;
147 int n, i;
148
149 n = sd_ndisc_router_dnssl_get_domains(rt, &l);
150 assert_se(n > 0);
151
152 for (i = 0; i < n; i++)
153 log_info("Domain: %s", l[i]);
154
155 assert_se(sd_ndisc_router_dnssl_get_lifetime(rt, &lifetime) >= 0);
156 assert_se(sd_ndisc_router_dnssl_get_lifetime_timestamp(rt, CLOCK_REALTIME, &t) >= 0);
157 log_info("Lifetime: %s (%s)", FORMAT_TIMESPAN(lifetime, USEC_PER_SEC), FORMAT_TIMESTAMP(t));
158 break;
159 }}
160
161 r = sd_ndisc_router_option_next(rt);
162 }
163 }
164
165 static int send_ra(uint8_t flags) {
166 uint8_t advertisement[] = {
167 0x86, 0x00, 0xde, 0x83, 0x40, 0xc0, 0x00, 0xb4,
168 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
169 0x03, 0x04, 0x40, 0xc0, 0x00, 0x00, 0x01, 0xf4,
170 0x00, 0x00, 0x01, 0xb8, 0x00, 0x00, 0x00, 0x00,
171 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
172 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
173 0x19, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
174 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
175 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
176 0x1f, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
177 0x03, 0x6c, 0x61, 0x62, 0x05, 0x69, 0x6e, 0x74,
178 0x72, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
179 0x01, 0x01, 0x78, 0x2b, 0xcb, 0xb3, 0x6d, 0x53,
180 };
181
182 advertisement[5] = flags;
183
184 assert_se(write(test_fd[1], advertisement, sizeof(advertisement)) ==
185 sizeof(advertisement));
186
187 if (verbose)
188 printf(" sent RA with flag 0x%02x\n", flags);
189
190 return 0;
191 }
192
193 static void test_callback(sd_ndisc *nd, sd_ndisc_event_t event, sd_ndisc_router *rt, void *userdata) {
194 sd_event *e = userdata;
195 static unsigned idx = 0;
196 uint64_t flags_array[] = {
197 0,
198 0,
199 0,
200 ND_RA_FLAG_OTHER,
201 ND_RA_FLAG_MANAGED
202 };
203 uint64_t flags;
204
205 assert_se(nd);
206
207 if (event != SD_NDISC_EVENT_ROUTER)
208 return;
209
210 router_dump(rt);
211
212 assert_se(sd_ndisc_router_get_flags(rt, &flags) >= 0);
213 assert_se(flags == flags_array[idx]);
214 idx++;
215
216 if (verbose)
217 printf(" got event 0x%02" PRIx64 "\n", flags);
218
219 if (idx < ELEMENTSOF(flags_array)) {
220 send_ra(flags_array[idx]);
221 return;
222 }
223
224 sd_event_exit(e, 0);
225 }
226
227 TEST(rs) {
228 _cleanup_(sd_event_unrefp) sd_event *e = NULL;
229 _cleanup_(sd_ndisc_unrefp) sd_ndisc *nd = NULL;
230
231 send_ra_function = send_ra;
232
233 assert_se(sd_event_new(&e) >= 0);
234
235 assert_se(sd_ndisc_new(&nd) >= 0);
236 assert_se(nd);
237
238 assert_se(sd_ndisc_attach_event(nd, e, 0) >= 0);
239
240 assert_se(sd_ndisc_set_ifindex(nd, 42) >= 0);
241 assert_se(sd_ndisc_set_mac(nd, &mac_addr) >= 0);
242 assert_se(sd_ndisc_set_callback(nd, test_callback, e) >= 0);
243
244 assert_se(sd_event_add_time_relative(e, NULL, CLOCK_BOOTTIME,
245 30 * USEC_PER_SEC, 0,
246 NULL, INT_TO_PTR(-ETIMEDOUT)) >= 0);
247
248 assert_se(sd_ndisc_stop(nd) >= 0);
249 assert_se(sd_ndisc_start(nd) >= 0);
250 assert_se(sd_ndisc_start(nd) >= 0);
251 assert_se(sd_ndisc_stop(nd) >= 0);
252 test_fd[1] = safe_close(test_fd[1]);
253
254 assert_se(sd_ndisc_start(nd) >= 0);
255
256 assert_se(sd_event_loop(e) >= 0);
257
258 test_fd[1] = safe_close(test_fd[1]);
259 }
260
261 static int test_timeout_value(uint8_t flags) {
262 static int count = 0;
263 static usec_t last = 0;
264 sd_ndisc *nd = test_timeout_nd;
265 usec_t min, max;
266
267 assert_se(nd);
268 assert_se(nd->event);
269
270 if (++count >= 20)
271 sd_event_exit(nd->event, 0);
272
273 if (last == 0) {
274 /* initial RT = IRT + RAND*IRT */
275 min = NDISC_ROUTER_SOLICITATION_INTERVAL -
276 NDISC_ROUTER_SOLICITATION_INTERVAL / 10;
277 max = NDISC_ROUTER_SOLICITATION_INTERVAL +
278 NDISC_ROUTER_SOLICITATION_INTERVAL / 10;
279 } else {
280 /* next RT = 2*RTprev + RAND*RTprev */
281 min = 2 * last - last / 10;
282 max = 2 * last + last / 10;
283 }
284
285 /* final RT > MRT */
286 if (last * 2 > NDISC_MAX_ROUTER_SOLICITATION_INTERVAL) {
287 min = NDISC_MAX_ROUTER_SOLICITATION_INTERVAL -
288 NDISC_MAX_ROUTER_SOLICITATION_INTERVAL / 10;
289 max = NDISC_MAX_ROUTER_SOLICITATION_INTERVAL +
290 NDISC_MAX_ROUTER_SOLICITATION_INTERVAL / 10;
291 }
292
293 log_info("backoff timeout interval %2d %s%s <= %s <= %s",
294 count,
295 last * 2 > NDISC_MAX_ROUTER_SOLICITATION_INTERVAL ? "(max) ": "",
296 FORMAT_TIMESPAN(min, USEC_PER_MSEC),
297 FORMAT_TIMESPAN(nd->retransmit_time, USEC_PER_MSEC),
298 FORMAT_TIMESPAN(max, USEC_PER_MSEC));
299
300 assert_se(min <= nd->retransmit_time);
301 assert_se(max >= nd->retransmit_time);
302
303 last = nd->retransmit_time;
304
305 assert_se(sd_event_source_set_time(nd->timeout_event_source, 0) >= 0);
306
307 return 0;
308 }
309
310 TEST(timeout) {
311 _cleanup_(sd_event_unrefp) sd_event *e = NULL;
312 _cleanup_(sd_ndisc_unrefp) sd_ndisc *nd = NULL;
313
314 send_ra_function = test_timeout_value;
315
316 assert_se(sd_event_new(&e) >= 0);
317
318 assert_se(sd_ndisc_new(&nd) >= 0);
319 assert_se(nd);
320
321 test_timeout_nd = nd;
322
323 assert_se(sd_ndisc_attach_event(nd, e, 0) >= 0);
324
325 assert_se(sd_ndisc_set_ifindex(nd, 42) >= 0);
326 assert_se(sd_ndisc_set_mac(nd, &mac_addr) >= 0);
327
328 assert_se(sd_event_add_time_relative(e, NULL, CLOCK_BOOTTIME,
329 30 * USEC_PER_SEC, 0,
330 NULL, INT_TO_PTR(-ETIMEDOUT)) >= 0);
331
332 assert_se(sd_ndisc_start(nd) >= 0);
333
334 assert_se(sd_event_loop(e) >= 0);
335
336 test_fd[1] = safe_close(test_fd[1]);
337 }
338
339 DEFINE_TEST_MAIN(LOG_DEBUG);