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