]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-radv.c
Revert "mkosi: turn off qemu headless mode"
[thirdparty/systemd.git] / src / network / networkd-radv.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
091214b6 2/***
810adae9 3 Copyright © 2017 Intel Corporation. All rights reserved.
091214b6
PF
4***/
5
6#include <netinet/icmp6.h>
7#include <arpa/inet.h>
8
ca5ad760 9#include "dns-domain.h"
b5ce4047 10#include "networkd-link.h"
c555a358 11#include "networkd-manager.h"
b5ce4047 12#include "networkd-network.h"
a254fab2 13#include "networkd-queue.h"
091214b6 14#include "networkd-radv.h"
6e849e95 15#include "parse-util.h"
6e849e95 16#include "string-util.h"
6b1dec66 17#include "string-table.h"
51517f9e 18#include "strv.h"
6e849e95 19
064dfb05 20Prefix *prefix_free(Prefix *prefix) {
6e849e95 21 if (!prefix)
064dfb05 22 return NULL;
6e849e95
PF
23
24 if (prefix->network) {
ecb0e85e
YW
25 assert(prefix->section);
26 hashmap_remove(prefix->network->prefixes_by_section, prefix->section);
6e849e95
PF
27 }
28
ecee0abe 29 network_config_section_free(prefix->section);
471e126b 30 sd_radv_prefix_unref(prefix->radv_prefix);
6e849e95 31
064dfb05 32 return mfree(prefix);
6e849e95
PF
33}
34
064dfb05
YW
35DEFINE_NETWORK_SECTION_FUNCTIONS(Prefix, prefix_free);
36
95081e08 37static int prefix_new(Prefix **ret) {
15b8332e 38 _cleanup_(prefix_freep) Prefix *prefix = NULL;
6e849e95
PF
39
40 prefix = new0(Prefix, 1);
41 if (!prefix)
42 return -ENOMEM;
43
44 if (sd_radv_prefix_new(&prefix->radv_prefix) < 0)
45 return -ENOMEM;
46
ae2a15bc 47 *ret = TAKE_PTR(prefix);
6e849e95
PF
48
49 return 0;
50}
51
a8d4a210 52static int prefix_new_static(Network *network, const char *filename, unsigned section_line, Prefix **ret) {
8e766630
LP
53 _cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL;
54 _cleanup_(prefix_freep) Prefix *prefix = NULL;
6e849e95
PF
55 int r;
56
57 assert(network);
58 assert(ret);
ecb0e85e
YW
59 assert(filename);
60 assert(section_line > 0);
6e849e95 61
ecb0e85e
YW
62 r = network_config_section_new(filename, section_line, &n);
63 if (r < 0)
64 return r;
6e849e95 65
ecb0e85e
YW
66 prefix = hashmap_get(network->prefixes_by_section, n);
67 if (prefix) {
68 *ret = TAKE_PTR(prefix);
69 return 0;
6e849e95
PF
70 }
71
72 r = prefix_new(&prefix);
73 if (r < 0)
74 return r;
75
0f7f2769 76 prefix->network = network;
ecb0e85e 77 prefix->section = TAKE_PTR(n);
6e849e95 78
b9eea0a7 79 r = hashmap_ensure_put(&network->prefixes_by_section, &network_config_hash_ops, prefix->section, prefix);
ecb0e85e
YW
80 if (r < 0)
81 return r;
6e849e95 82
1cc6c93a 83 *ret = TAKE_PTR(prefix);
6e849e95
PF
84
85 return 0;
86}
87
064dfb05 88RoutePrefix *route_prefix_free(RoutePrefix *prefix) {
203d4df5 89 if (!prefix)
064dfb05 90 return NULL;
203d4df5
SS
91
92 if (prefix->network) {
ecb0e85e
YW
93 assert(prefix->section);
94 hashmap_remove(prefix->network->route_prefixes_by_section, prefix->section);
203d4df5
SS
95 }
96
97 network_config_section_free(prefix->section);
471e126b 98 sd_radv_route_prefix_unref(prefix->radv_route_prefix);
203d4df5 99
064dfb05
YW
100 return mfree(prefix);
101}
102
103DEFINE_NETWORK_SECTION_FUNCTIONS(RoutePrefix, route_prefix_free);
104
105static int route_prefix_new(RoutePrefix **ret) {
106 _cleanup_(route_prefix_freep) RoutePrefix *prefix = NULL;
107
108 prefix = new0(RoutePrefix, 1);
109 if (!prefix)
110 return -ENOMEM;
111
112 if (sd_radv_route_prefix_new(&prefix->radv_route_prefix) < 0)
113 return -ENOMEM;
114
115 *ret = TAKE_PTR(prefix);
116
117 return 0;
203d4df5
SS
118}
119
a8d4a210 120static int route_prefix_new_static(Network *network, const char *filename, unsigned section_line, RoutePrefix **ret) {
203d4df5 121 _cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL;
95081e08 122 _cleanup_(route_prefix_freep) RoutePrefix *prefix = NULL;
203d4df5
SS
123 int r;
124
125 assert(network);
126 assert(ret);
ecb0e85e
YW
127 assert(filename);
128 assert(section_line > 0);
203d4df5 129
ecb0e85e
YW
130 r = network_config_section_new(filename, section_line, &n);
131 if (r < 0)
132 return r;
203d4df5 133
ecb0e85e
YW
134 prefix = hashmap_get(network->route_prefixes_by_section, n);
135 if (prefix) {
136 *ret = TAKE_PTR(prefix);
137 return 0;
203d4df5
SS
138 }
139
140 r = route_prefix_new(&prefix);
141 if (r < 0)
142 return r;
143
144 prefix->network = network;
ecb0e85e 145 prefix->section = TAKE_PTR(n);
203d4df5 146
b2cb2e82 147 r = hashmap_ensure_put(&network->route_prefixes_by_section, &network_config_hash_ops, prefix->section, prefix);
ecb0e85e
YW
148 if (r < 0)
149 return r;
203d4df5
SS
150
151 *ret = TAKE_PTR(prefix);
152
153 return 0;
154}
155
13ffa39f 156void network_drop_invalid_prefixes(Network *network) {
1a7deb2f
YW
157 Prefix *prefix;
158
159 assert(network);
160
161 HASHMAP_FOREACH(prefix, network->prefixes_by_section)
162 if (section_is_invalid(prefix->section))
163 prefix_free(prefix);
164}
165
13ffa39f 166void network_drop_invalid_route_prefixes(Network *network) {
1a7deb2f
YW
167 RoutePrefix *prefix;
168
169 assert(network);
170
171 HASHMAP_FOREACH(prefix, network->route_prefixes_by_section)
172 if (section_is_invalid(prefix->section))
173 route_prefix_free(prefix);
174}
175
69e0f833
YW
176void network_adjust_radv(Network *network) {
177 assert(network);
178
e502f94d
YW
179 /* After this function is called, network->router_prefix_delegation can be treated as a boolean. */
180
181 if (network->dhcp6_pd < 0)
182 /* For backward compatibility. */
183 network->dhcp6_pd = FLAGS_SET(network->router_prefix_delegation, RADV_PREFIX_DELEGATION_DHCP6);
184
69e0f833
YW
185 if (!FLAGS_SET(network->link_local, ADDRESS_FAMILY_IPV6)) {
186 if (network->router_prefix_delegation != RADV_PREFIX_DELEGATION_NONE)
187 log_warning("%s: IPv6PrefixDelegation= is enabled but IPv6 link local addressing is disabled. "
188 "Disabling IPv6PrefixDelegation=.", network->filename);
189
190 network->router_prefix_delegation = RADV_PREFIX_DELEGATION_NONE;
191 }
192
193 if (network->router_prefix_delegation == RADV_PREFIX_DELEGATION_NONE) {
194 network->n_router_dns = 0;
195 network->router_dns = mfree(network->router_dns);
196 network->router_search_domains = ordered_set_free(network->router_search_domains);
8a08bbfc
YW
197 }
198
199 if (!FLAGS_SET(network->router_prefix_delegation, RADV_PREFIX_DELEGATION_STATIC)) {
69e0f833
YW
200 network->prefixes_by_section = hashmap_free_with_destructor(network->prefixes_by_section, prefix_free);
201 network->route_prefixes_by_section = hashmap_free_with_destructor(network->route_prefixes_by_section, route_prefix_free);
202 }
203}
204
a8d4a210
YW
205int config_parse_prefix(
206 const char *unit,
207 const char *filename,
208 unsigned line,
209 const char *section,
210 unsigned section_line,
211 const char *lvalue,
212 int ltype,
213 const char *rvalue,
214 void *data,
215 void *userdata) {
6e849e95
PF
216
217 Network *network = userdata;
fcbf4cb7 218 _cleanup_(prefix_free_or_set_invalidp) Prefix *p = NULL;
6e849e95
PF
219 uint8_t prefixlen = 64;
220 union in_addr_union in6addr;
221 int r;
222
223 assert(filename);
224 assert(section);
225 assert(lvalue);
226 assert(rvalue);
227 assert(data);
228
229 r = prefix_new_static(network, filename, section_line, &p);
230 if (r < 0)
d96edb2c 231 return log_oom();
6e849e95
PF
232
233 r = in_addr_prefix_from_string(rvalue, AF_INET6, &in6addr, &prefixlen);
234 if (r < 0) {
d96edb2c 235 log_syntax(unit, LOG_WARNING, filename, line, r, "Prefix is invalid, ignoring assignment: %s", rvalue);
6e849e95
PF
236 return 0;
237 }
238
c9778516
YW
239 r = sd_radv_prefix_set_prefix(p->radv_prefix, &in6addr.in6, prefixlen);
240 if (r < 0) {
241 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to set radv prefix, ignoring assignment: %s", rvalue);
242 return 0;
243 }
6e849e95
PF
244
245 p = NULL;
246
247 return 0;
248}
249
a8d4a210
YW
250int config_parse_prefix_flags(
251 const char *unit,
252 const char *filename,
253 unsigned line,
254 const char *section,
255 unsigned section_line,
256 const char *lvalue,
257 int ltype,
258 const char *rvalue,
259 void *data,
260 void *userdata) {
261
6e849e95 262 Network *network = userdata;
fcbf4cb7 263 _cleanup_(prefix_free_or_set_invalidp) Prefix *p = NULL;
c9778516 264 int r;
6e849e95
PF
265
266 assert(filename);
267 assert(section);
268 assert(lvalue);
269 assert(rvalue);
270 assert(data);
271
272 r = prefix_new_static(network, filename, section_line, &p);
273 if (r < 0)
d96edb2c 274 return log_oom();
6e849e95
PF
275
276 r = parse_boolean(rvalue);
277 if (r < 0) {
c9778516 278 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse %s=, ignoring assignment: %s", lvalue, rvalue);
6e849e95
PF
279 return 0;
280 }
281
6e849e95 282 if (streq(lvalue, "OnLink"))
c9778516 283 r = sd_radv_prefix_set_onlink(p->radv_prefix, r);
6e849e95 284 else if (streq(lvalue, "AddressAutoconfiguration"))
c9778516
YW
285 r = sd_radv_prefix_set_address_autoconfiguration(p->radv_prefix, r);
286 if (r < 0) {
287 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to set %s=, ignoring assignment: %m", lvalue);
288 return 0;
289 }
6e849e95
PF
290
291 p = NULL;
292
293 return 0;
294}
295
a8d4a210
YW
296int config_parse_prefix_lifetime(
297 const char *unit,
298 const char *filename,
299 unsigned line,
300 const char *section,
301 unsigned section_line,
302 const char *lvalue,
303 int ltype,
304 const char *rvalue,
305 void *data,
306 void *userdata) {
307
6e849e95 308 Network *network = userdata;
fcbf4cb7 309 _cleanup_(prefix_free_or_set_invalidp) Prefix *p = NULL;
6e849e95
PF
310 usec_t usec;
311 int r;
312
313 assert(filename);
314 assert(section);
315 assert(lvalue);
316 assert(rvalue);
317 assert(data);
318
319 r = prefix_new_static(network, filename, section_line, &p);
320 if (r < 0)
d96edb2c 321 return log_oom();
6e849e95
PF
322
323 r = parse_sec(rvalue, &usec);
324 if (r < 0) {
d96edb2c 325 log_syntax(unit, LOG_WARNING, filename, line, r, "Lifetime is invalid, ignoring assignment: %s", rvalue);
6e849e95
PF
326 return 0;
327 }
328
329 /* a value of 0xffffffff represents infinity */
330 if (streq(lvalue, "PreferredLifetimeSec"))
331 r = sd_radv_prefix_set_preferred_lifetime(p->radv_prefix,
332 DIV_ROUND_UP(usec, USEC_PER_SEC));
333 else if (streq(lvalue, "ValidLifetimeSec"))
334 r = sd_radv_prefix_set_valid_lifetime(p->radv_prefix,
335 DIV_ROUND_UP(usec, USEC_PER_SEC));
c9778516
YW
336 if (r < 0) {
337 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to set %s=, ignoring assignment: %m", lvalue);
338 return 0;
339 }
6e849e95
PF
340
341 p = NULL;
342
343 return 0;
344}
091214b6 345
bd6379ec
SS
346int config_parse_prefix_assign(
347 const char *unit,
348 const char *filename,
349 unsigned line,
350 const char *section,
351 unsigned section_line,
352 const char *lvalue,
353 int ltype,
354 const char *rvalue,
355 void *data,
356 void *userdata) {
357
358 Network *network = userdata;
359 _cleanup_(prefix_free_or_set_invalidp) Prefix *p = NULL;
360 int r;
361
362 assert(filename);
363 assert(section);
364 assert(lvalue);
365 assert(rvalue);
366 assert(data);
367
368 r = prefix_new_static(network, filename, section_line, &p);
369 if (r < 0)
d96edb2c 370 return log_oom();
bd6379ec
SS
371
372 r = parse_boolean(rvalue);
373 if (r < 0) {
d96edb2c 374 log_syntax(unit, LOG_WARNING, filename, line, r,
bd6379ec
SS
375 "Failed to parse %s=, ignoring assignment: %s",
376 lvalue, rvalue);
377 return 0;
378 }
379
380 p->assign = r;
381 p = NULL;
382
383 return 0;
384}
385
0e1fb1d0
YW
386int config_parse_prefix_metric(
387 const char *unit,
388 const char *filename,
389 unsigned line,
390 const char *section,
391 unsigned section_line,
392 const char *lvalue,
393 int ltype,
394 const char *rvalue,
395 void *data,
396 void *userdata) {
397
398 Network *network = userdata;
399 _cleanup_(prefix_free_or_set_invalidp) Prefix *p = NULL;
400 int r;
401
402 assert(filename);
403 assert(section);
404 assert(lvalue);
405 assert(rvalue);
406 assert(data);
407
408 r = prefix_new_static(network, filename, section_line, &p);
409 if (r < 0)
410 return log_oom();
411
412 r = safe_atou32(rvalue, &p->route_metric);
413 if (r < 0) {
414 log_syntax(unit, LOG_WARNING, filename, line, r,
415 "Failed to parse %s=, ignoring assignment: %s",
416 lvalue, rvalue);
417 return 0;
418 }
419
420 TAKE_PTR(p);
421
422 return 0;
423}
424
a8d4a210
YW
425int config_parse_route_prefix(
426 const char *unit,
427 const char *filename,
428 unsigned line,
429 const char *section,
430 unsigned section_line,
431 const char *lvalue,
432 int ltype,
433 const char *rvalue,
434 void *data,
435 void *userdata) {
203d4df5
SS
436
437 Network *network = userdata;
95081e08 438 _cleanup_(route_prefix_free_or_set_invalidp) RoutePrefix *p = NULL;
203d4df5
SS
439 uint8_t prefixlen = 64;
440 union in_addr_union in6addr;
441 int r;
442
443 assert(filename);
444 assert(section);
445 assert(lvalue);
446 assert(rvalue);
447 assert(data);
448
449 r = route_prefix_new_static(network, filename, section_line, &p);
450 if (r < 0)
d96edb2c 451 return log_oom();
203d4df5
SS
452
453 r = in_addr_prefix_from_string(rvalue, AF_INET6, &in6addr, &prefixlen);
454 if (r < 0) {
d96edb2c 455 log_syntax(unit, LOG_WARNING, filename, line, r, "Route prefix is invalid, ignoring assignment: %s", rvalue);
203d4df5
SS
456 return 0;
457 }
458
c9778516
YW
459 r = sd_radv_prefix_set_route_prefix(p->radv_route_prefix, &in6addr.in6, prefixlen);
460 if (r < 0) {
461 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to set route prefix, ignoring assignment: %m");
462 return 0;
463 }
203d4df5
SS
464
465 p = NULL;
466
467 return 0;
468}
469
a8d4a210
YW
470int config_parse_route_prefix_lifetime(
471 const char *unit,
472 const char *filename,
473 unsigned line,
474 const char *section,
475 unsigned section_line,
476 const char *lvalue,
477 int ltype,
478 const char *rvalue,
479 void *data,
480 void *userdata) {
481
203d4df5 482 Network *network = userdata;
95081e08 483 _cleanup_(route_prefix_free_or_set_invalidp) RoutePrefix *p = NULL;
203d4df5
SS
484 usec_t usec;
485 int r;
486
487 assert(filename);
488 assert(section);
489 assert(lvalue);
490 assert(rvalue);
491 assert(data);
492
493 r = route_prefix_new_static(network, filename, section_line, &p);
494 if (r < 0)
d96edb2c 495 return log_oom();
203d4df5
SS
496
497 r = parse_sec(rvalue, &usec);
498 if (r < 0) {
d96edb2c 499 log_syntax(unit, LOG_WARNING, filename, line, r,
095b3a7d 500 "Route lifetime is invalid, ignoring assignment: %s", rvalue);
203d4df5
SS
501 return 0;
502 }
503
504 /* a value of 0xffffffff represents infinity */
505 r = sd_radv_route_prefix_set_lifetime(p->radv_route_prefix, DIV_ROUND_UP(usec, USEC_PER_SEC));
c9778516
YW
506 if (r < 0) {
507 log_syntax(unit, LOG_WARNING, filename, line, r,
508 "Failed to set route lifetime, ignoring assignment: %m");
509 return 0;
510 }
203d4df5
SS
511
512 p = NULL;
513
514 return 0;
515}
516
be023c67 517static int network_get_ipv6_dns(Network *network, struct in6_addr **ret_addresses, size_t *ret_size) {
c555a358 518 _cleanup_free_ struct in6_addr *addresses = NULL;
319a4f4b 519 size_t n_addresses = 0;
c555a358
PF
520
521 assert(network);
be023c67
YW
522 assert(ret_addresses);
523 assert(ret_size);
c555a358 524
be023c67 525 for (size_t i = 0; i < network->n_dns; i++) {
c555a358
PF
526 union in_addr_union *addr;
527
e77bd3fd 528 if (network->dns[i]->family != AF_INET6)
c555a358
PF
529 continue;
530
e77bd3fd 531 addr = &network->dns[i]->address;
c555a358
PF
532
533 if (in_addr_is_null(AF_INET6, addr) ||
534 in_addr_is_link_local(AF_INET6, addr) ||
535 in_addr_is_localhost(AF_INET6, addr))
536 continue;
537
319a4f4b 538 if (!GREEDY_REALLOC(addresses, n_addresses + 1))
c555a358
PF
539 return -ENOMEM;
540
541 addresses[n_addresses++] = addr->in6;
542 }
543
be023c67
YW
544 *ret_addresses = TAKE_PTR(addresses);
545 *ret_size = n_addresses;
c555a358
PF
546
547 return n_addresses;
548}
549
550static int radv_set_dns(Link *link, Link *uplink) {
551 _cleanup_free_ struct in6_addr *dns = NULL;
c555a358 552 usec_t lifetime_usec;
fd3ef936 553 size_t n_dns;
c555a358
PF
554 int r;
555
556 if (!link->network->router_emit_dns)
557 return 0;
558
559 if (link->network->router_dns) {
fd3ef936
YW
560 struct in6_addr *p;
561
562 dns = new(struct in6_addr, link->network->n_router_dns);
4e361acc 563 if (!dns)
c555a358
PF
564 return -ENOMEM;
565
fd3ef936
YW
566 p = dns;
567 for (size_t i = 0; i < link->network->n_router_dns; i++)
94876904
YW
568 if (in6_addr_is_null(&link->network->router_dns[i])) {
569 if (in6_addr_is_set(&link->ipv6ll_address))
fd3ef936
YW
570 *(p++) = link->ipv6ll_address;
571 } else
572 *(p++) = link->network->router_dns[i];
573
574 n_dns = p - dns;
c555a358
PF
575 lifetime_usec = link->network->router_dns_lifetime_usec;
576
577 goto set_dns;
578 }
579
580 lifetime_usec = SD_RADV_DEFAULT_DNS_LIFETIME_USEC;
581
be023c67 582 r = network_get_ipv6_dns(link->network, &dns, &n_dns);
c555a358
PF
583 if (r > 0)
584 goto set_dns;
585
586 if (uplink) {
63295b42 587 assert(uplink->network);
349a981d 588
be023c67 589 r = network_get_ipv6_dns(uplink->network, &dns, &n_dns);
c555a358
PF
590 if (r > 0)
591 goto set_dns;
592 }
593
594 return 0;
595
a254fab2 596set_dns:
c555a358
PF
597 return sd_radv_set_rdnss(link->radv,
598 DIV_ROUND_UP(lifetime_usec, USEC_PER_SEC),
599 dns, n_dns);
600}
601
602static int radv_set_domains(Link *link, Link *uplink) {
5e2a51d5 603 OrderedSet *search_domains;
c555a358 604 usec_t lifetime_usec;
5e2a51d5 605 _cleanup_free_ char **s = NULL; /* just free() because the strings are owned by the set */
c555a358
PF
606
607 if (!link->network->router_emit_domains)
608 return 0;
609
610 search_domains = link->network->router_search_domains;
611 lifetime_usec = link->network->router_dns_lifetime_usec;
612
613 if (search_domains)
614 goto set_domains;
615
616 lifetime_usec = SD_RADV_DEFAULT_DNS_LIFETIME_USEC;
617
618 search_domains = link->network->search_domains;
619 if (search_domains)
620 goto set_domains;
621
622 if (uplink) {
63295b42 623 assert(uplink->network);
349a981d 624
c555a358
PF
625 search_domains = uplink->network->search_domains;
626 if (search_domains)
627 goto set_domains;
628 }
629
630 return 0;
631
a254fab2 632set_domains:
5e2a51d5
ZJS
633 s = ordered_set_get_strv(search_domains);
634 if (!s)
635 return log_oom();
636
c555a358
PF
637 return sd_radv_set_dnssl(link->radv,
638 DIV_ROUND_UP(lifetime_usec, USEC_PER_SEC),
5e2a51d5 639 s);
c555a358
PF
640
641}
642
63295b42
YW
643static int radv_find_uplink(Link *link, Link **ret) {
644 assert(link);
645
646 if (link->network->router_uplink_name)
647 return link_get_by_name(link->manager, link->network->router_uplink_name, ret);
648
649 if (link->network->router_uplink_index > 0)
650 return link_get_by_index(link->manager, link->network->router_uplink_index, ret);
651
652 if (link->network->router_uplink_index == UPLINK_INDEX_AUTO) {
653 /* It is not necessary to propagate error in automatic selection. */
654 if (manager_find_uplink(link->manager, AF_INET6, link, ret) < 0)
655 *ret = NULL;
656 return 0;
657 }
658
659 *ret = NULL;
660 return 0;
661}
662
086b8853
YW
663static bool link_radv_enabled(Link *link) {
664 assert(link);
665
666 if (!link_ipv6ll_enabled(link))
667 return false;
668
e502f94d 669 return link->network->router_prefix_delegation;
086b8853
YW
670}
671
a254fab2 672static int radv_configure(Link *link) {
2075e596 673 uint16_t router_lifetime;
a254fab2 674 Link *uplink = NULL;
8a08bbfc
YW
675 RoutePrefix *q;
676 Prefix *p;
95081e08 677 int r;
091214b6
PF
678
679 assert(link);
680 assert(link->network);
681
bc9e40c9
YW
682 if (link->radv)
683 return -EBUSY;
684
091214b6
PF
685 r = sd_radv_new(&link->radv);
686 if (r < 0)
687 return r;
688
4cf85000 689 r = sd_radv_attach_event(link->radv, link->manager->event, 0);
091214b6
PF
690 if (r < 0)
691 return r;
692
ca2b7cd8 693 r = sd_radv_set_mac(link->radv, &link->hw_addr.ether);
091214b6
PF
694 if (r < 0)
695 return r;
696
697 r = sd_radv_set_ifindex(link->radv, link->ifindex);
698 if (r < 0)
699 return r;
700
701 r = sd_radv_set_managed_information(link->radv, link->network->router_managed);
702 if (r < 0)
703 return r;
704
705 r = sd_radv_set_other_information(link->radv, link->network->router_other_information);
706 if (r < 0)
707 return r;
708
2075e596
YW
709 /* a value of UINT16_MAX represents infinity, 0x0 means this host is not a router */
710 if (link->network->router_lifetime_usec == USEC_INFINITY)
711 router_lifetime = UINT16_MAX;
712 else if (link->network->router_lifetime_usec > (UINT16_MAX - 1) * USEC_PER_SEC)
713 router_lifetime = UINT16_MAX - 1;
714 else
715 router_lifetime = DIV_ROUND_UP(link->network->router_lifetime_usec, USEC_PER_SEC);
716
717 r = sd_radv_set_router_lifetime(link->radv, router_lifetime);
091214b6
PF
718 if (r < 0)
719 return r;
720
2075e596
YW
721 if (router_lifetime > 0) {
722 r = sd_radv_set_preference(link->radv, link->network->router_preference);
091214b6
PF
723 if (r < 0)
724 return r;
725 }
726
8a08bbfc
YW
727 HASHMAP_FOREACH(p, link->network->prefixes_by_section) {
728 r = sd_radv_add_prefix(link->radv, p->radv_prefix, false);
729 if (r == -EEXIST)
730 continue;
731 if (r == -ENOEXEC) {
732 log_link_warning_errno(link, r, "[IPv6Prefix] section configured without Prefix= setting, ignoring section.");
733 continue;
56a23cb4 734 }
8a08bbfc
YW
735 if (r < 0)
736 return r;
737 }
203d4df5 738
8a08bbfc
YW
739 HASHMAP_FOREACH(q, link->network->route_prefixes_by_section) {
740 r = sd_radv_add_route_prefix(link->radv, q->radv_route_prefix, false);
741 if (r == -EEXIST)
742 continue;
743 if (r < 0)
744 return r;
091214b6
PF
745 }
746
63295b42 747 (void) radv_find_uplink(link, &uplink);
a254fab2
YW
748
749 r = radv_set_dns(link, uplink);
750 if (r < 0)
751 return log_link_debug_errno(link, r, "Could not set RA DNS: %m");
752
753 r = radv_set_domains(link, uplink);
754 if (r < 0)
755 return log_link_debug_errno(link, r, "Could not set RA Domains: %m");
756
fd3ef936 757 return 0;
091214b6 758}
ca5ad760 759
be9363cc
YW
760int radv_update_mac(Link *link) {
761 bool restart;
762 int r;
763
764 assert(link);
765
766 if (!link->radv)
767 return 0;
768
769 restart = sd_radv_is_running(link->radv);
770
a391901e
YW
771 r = sd_radv_stop(link->radv);
772 if (r < 0)
773 return r;
be9363cc 774
ca2b7cd8 775 r = sd_radv_set_mac(link->radv, &link->hw_addr.ether);
be9363cc
YW
776 if (r < 0)
777 return r;
778
779 if (restart) {
780 r = sd_radv_start(link->radv);
781 if (r < 0)
782 return r;
783 }
784
785 return 0;
786}
787
63295b42
YW
788static int radv_is_ready_to_configure(Link *link) {
789 bool needs_uplink = false;
790 int r;
791
a254fab2
YW
792 assert(link);
793 assert(link->network);
794
795 if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
796 return false;
797
798 if (in6_addr_is_null(&link->ipv6ll_address))
799 return false;
800
63295b42
YW
801 if (link->network->router_emit_dns && !link->network->router_dns) {
802 _cleanup_free_ struct in6_addr *dns = NULL;
803 size_t n_dns;
804
805 r = network_get_ipv6_dns(link->network, &dns, &n_dns);
806 if (r < 0)
807 return r;
808
809 needs_uplink = r == 0;
810 }
811
812 if (link->network->router_emit_domains &&
813 !link->network->router_search_domains &&
814 !link->network->search_domains)
815 needs_uplink = true;
816
817 if (needs_uplink) {
818 Link *uplink = NULL;
819
820 if (radv_find_uplink(link, &uplink) < 0)
821 return false;
822
823 if (uplink && !uplink->network)
824 return false;
825 }
826
a254fab2
YW
827 return true;
828}
829
830int request_process_radv(Request *req) {
831 Link *link;
832 int r;
833
834 assert(req);
835 assert(req->link);
836 assert(req->type == REQUEST_TYPE_RADV);
837
838 link = req->link;
839
63295b42
YW
840 r = radv_is_ready_to_configure(link);
841 if (r <= 0)
842 return r;
a254fab2
YW
843
844 r = radv_configure(link);
845 if (r < 0)
846 return log_link_warning_errno(link, r, "Failed to configure IPv6 Router Advertisement engine: %m");
847
848 if (link_has_carrier(link)) {
849 r = sd_radv_start(link->radv);
850 if (r < 0)
851 return log_link_warning_errno(link, r, "Failed to start IPv6 Router Advertisement engine: %m");
852 }
853
854 log_link_debug(link, "IPv6 Router Advertisement engine is configured%s.",
855 link_has_carrier(link) ? " and started." : "");
856 return 1;
857}
858
859int link_request_radv(Link *link) {
860 int r;
861
862 assert(link);
863
864 if (!link_radv_enabled(link))
865 return 0;
866
867 if (link->radv)
868 return 0;
869
870 r = link_queue_request(link, REQUEST_TYPE_RADV, NULL, false, NULL, NULL, NULL);
871 if (r < 0)
b378b150 872 return log_link_warning_errno(link, r, "Failed to request configuring of the IPv6 Router Advertisement engine: %m");
a254fab2 873
b378b150 874 log_link_debug(link, "Requested configuring of the IPv6 Router Advertisement engine.");
a254fab2
YW
875 return 0;
876}
877
a8d4a210
YW
878int radv_add_prefix(
879 Link *link,
880 const struct in6_addr *prefix,
881 uint8_t prefix_len,
882 uint32_t lifetime_preferred,
883 uint32_t lifetime_valid) {
884
1d596fde
YW
885 _cleanup_(sd_radv_prefix_unrefp) sd_radv_prefix *p = NULL;
886 int r;
887
888 assert(link);
85b6a811
YW
889
890 if (!link->radv)
891 return 0;
1d596fde
YW
892
893 r = sd_radv_prefix_new(&p);
894 if (r < 0)
895 return r;
896
897 r = sd_radv_prefix_set_prefix(p, prefix, prefix_len);
898 if (r < 0)
899 return r;
900
901 r = sd_radv_prefix_set_preferred_lifetime(p, lifetime_preferred);
902 if (r < 0)
903 return r;
904
905 r = sd_radv_prefix_set_valid_lifetime(p, lifetime_valid);
906 if (r < 0)
907 return r;
908
909 r = sd_radv_add_prefix(link->radv, p, true);
910 if (r < 0 && r != -EEXIST)
911 return r;
912
913 return 0;
914}
915
ca5ad760
YW
916int config_parse_radv_dns(
917 const char *unit,
918 const char *filename,
919 unsigned line,
920 const char *section,
921 unsigned section_line,
922 const char *lvalue,
923 int ltype,
924 const char *rvalue,
925 void *data,
926 void *userdata) {
927
928 Network *n = data;
ca5ad760
YW
929 int r;
930
931 assert(filename);
932 assert(lvalue);
933 assert(rvalue);
934
a3c1a949
YW
935 if (isempty(rvalue)) {
936 n->n_router_dns = 0;
937 n->router_dns = mfree(n->router_dns);
938 return 0;
939 }
940
d96edb2c 941 for (const char *p = rvalue;;) {
ca5ad760
YW
942 _cleanup_free_ char *w = NULL;
943 union in_addr_union a;
944
945 r = extract_first_word(&p, &w, NULL, 0);
946 if (r == -ENOMEM)
947 return log_oom();
948 if (r < 0) {
d96edb2c 949 log_syntax(unit, LOG_WARNING, filename, line, r,
ca5ad760
YW
950 "Failed to extract word, ignoring: %s", rvalue);
951 return 0;
952 }
953 if (r == 0)
d96edb2c 954 return 0;
ca5ad760 955
fd3ef936
YW
956 if (streq(w, "_link_local"))
957 a = IN_ADDR_NULL;
958 else {
959 r = in_addr_from_string(AF_INET6, w, &a);
960 if (r < 0) {
d96edb2c 961 log_syntax(unit, LOG_WARNING, filename, line, r,
fd3ef936
YW
962 "Failed to parse DNS server address, ignoring: %s", w);
963 continue;
964 }
ca5ad760 965
fd3ef936 966 if (in_addr_is_null(AF_INET6, &a)) {
d96edb2c 967 log_syntax(unit, LOG_WARNING, filename, line, 0,
fd3ef936
YW
968 "DNS server address is null, ignoring: %s", w);
969 continue;
970 }
971 }
ca5ad760 972
fd3ef936
YW
973 struct in6_addr *m;
974 m = reallocarray(n->router_dns, n->n_router_dns + 1, sizeof(struct in6_addr));
975 if (!m)
976 return log_oom();
ca5ad760 977
fd3ef936
YW
978 m[n->n_router_dns++] = a.in6;
979 n->router_dns = m;
ca5ad760 980 }
ca5ad760
YW
981}
982
983int config_parse_radv_search_domains(
984 const char *unit,
985 const char *filename,
986 unsigned line,
987 const char *section,
988 unsigned section_line,
989 const char *lvalue,
990 int ltype,
991 const char *rvalue,
992 void *data,
993 void *userdata) {
994
995 Network *n = data;
ca5ad760
YW
996 int r;
997
998 assert(filename);
999 assert(lvalue);
1000 assert(rvalue);
1001
a3c1a949
YW
1002 if (isempty(rvalue)) {
1003 n->router_search_domains = ordered_set_free(n->router_search_domains);
1004 return 0;
1005 }
1006
d96edb2c 1007 for (const char *p = rvalue;;) {
ca5ad760
YW
1008 _cleanup_free_ char *w = NULL, *idna = NULL;
1009
1010 r = extract_first_word(&p, &w, NULL, 0);
1011 if (r == -ENOMEM)
1012 return log_oom();
1013 if (r < 0) {
d96edb2c 1014 log_syntax(unit, LOG_WARNING, filename, line, r,
ca5ad760
YW
1015 "Failed to extract word, ignoring: %s", rvalue);
1016 return 0;
1017 }
1018 if (r == 0)
d96edb2c 1019 return 0;
ca5ad760
YW
1020
1021 r = dns_name_apply_idna(w, &idna);
1022 if (r < 0) {
d96edb2c 1023 log_syntax(unit, LOG_WARNING, filename, line, r,
ca5ad760
YW
1024 "Failed to apply IDNA to domain name '%s', ignoring: %m", w);
1025 continue;
1026 } else if (r == 0)
1027 /* transfer ownership to simplify subsequent operations */
1028 idna = TAKE_PTR(w);
1029
5e276772 1030 r = ordered_set_ensure_allocated(&n->router_search_domains, &string_hash_ops_free);
ca5ad760 1031 if (r < 0)
d96edb2c 1032 return log_oom();
ca5ad760
YW
1033
1034 r = ordered_set_consume(n->router_search_domains, TAKE_PTR(idna));
1035 if (r < 0)
d96edb2c 1036 return log_oom();
ca5ad760 1037 }
ca5ad760
YW
1038}
1039
1040static const char * const radv_prefix_delegation_table[_RADV_PREFIX_DELEGATION_MAX] = {
a8d4a210 1041 [RADV_PREFIX_DELEGATION_NONE] = "no",
ca5ad760 1042 [RADV_PREFIX_DELEGATION_STATIC] = "static",
a8d4a210
YW
1043 [RADV_PREFIX_DELEGATION_DHCP6] = "dhcpv6",
1044 [RADV_PREFIX_DELEGATION_BOTH] = "yes",
ca5ad760
YW
1045};
1046
1047DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(
1048 radv_prefix_delegation,
1049 RADVPrefixDelegation,
1050 RADV_PREFIX_DELEGATION_BOTH);
1051
27ff0490
YW
1052int config_parse_router_prefix_delegation(
1053 const char *unit,
1054 const char *filename,
1055 unsigned line,
1056 const char *section,
1057 unsigned section_line,
1058 const char *lvalue,
1059 int ltype,
1060 const char *rvalue,
1061 void *data,
1062 void *userdata) {
1063
1064 RADVPrefixDelegation val, *ra = data;
1065 int r;
1066
1067 assert(filename);
1068 assert(lvalue);
1069 assert(rvalue);
1070 assert(data);
1071
1072 if (streq(lvalue, "IPv6SendRA")) {
1073 r = parse_boolean(rvalue);
1074 if (r < 0) {
1075 log_syntax(unit, LOG_WARNING, filename, line, r,
1076 "Invalid %s= setting, ignoring assignment: %s", lvalue, rvalue);
1077 return 0;
1078 }
1079
1080 /* When IPv6SendRA= is enabled, only static prefixes are sent by default, and users
1081 * need to explicitly enable DHCPv6PrefixDelegation=. */
1082 *ra = r ? RADV_PREFIX_DELEGATION_STATIC : RADV_PREFIX_DELEGATION_NONE;
1083 return 0;
1084 }
1085
1086 /* For backward compatibility */
1087 val = radv_prefix_delegation_from_string(rvalue);
1088 if (val < 0) {
b98680b2 1089 log_syntax(unit, LOG_WARNING, filename, line, val,
27ff0490
YW
1090 "Invalid %s= setting, ignoring assignment: %s", lvalue, rvalue);
1091 return 0;
1092 }
1093
1094 *ra = val;
1095 return 0;
1096}
a8d4a210
YW
1097
1098int config_parse_router_preference(
1099 const char *unit,
1100 const char *filename,
1101 unsigned line,
1102 const char *section,
1103 unsigned section_line,
1104 const char *lvalue,
1105 int ltype,
1106 const char *rvalue,
1107 void *data,
1108 void *userdata) {
1109
ca5ad760
YW
1110 Network *network = userdata;
1111
1112 assert(filename);
1113 assert(section);
1114 assert(lvalue);
1115 assert(rvalue);
1116 assert(data);
1117
1118 if (streq(rvalue, "high"))
1119 network->router_preference = SD_NDISC_PREFERENCE_HIGH;
1120 else if (STR_IN_SET(rvalue, "medium", "normal", "default"))
1121 network->router_preference = SD_NDISC_PREFERENCE_MEDIUM;
1122 else if (streq(rvalue, "low"))
1123 network->router_preference = SD_NDISC_PREFERENCE_LOW;
1124 else
d96edb2c
YW
1125 log_syntax(unit, LOG_WARNING, filename, line, 0,
1126 "Invalid router preference, ignoring assignment: %s", rvalue);
ca5ad760
YW
1127
1128 return 0;
1129}