1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
3 #include <linux/ipv6_route.h>
5 #include "dhcp6-lease-internal.h"
7 #include "in-addr-prefix-util.h"
8 #include "networkd-address-generation.h"
9 #include "networkd-address.h"
10 #include "networkd-dhcp-prefix-delegation.h"
11 #include "networkd-dhcp6.h"
12 #include "networkd-link.h"
13 #include "networkd-manager.h"
14 #include "networkd-queue.h"
15 #include "networkd-radv.h"
16 #include "networkd-route.h"
17 #include "networkd-setlink.h"
18 #include "parse-util.h"
19 #include "string-util.h"
23 bool link_dhcp_pd_is_enabled(Link
*link
) {
29 return link
->network
->dhcp_pd
;
32 bool dhcp_pd_is_uplink(Link
*link
, Link
*target
, bool accept_auto
) {
36 if (!link_dhcp_pd_is_enabled(link
))
39 if (link
->network
->dhcp_pd_uplink_name
)
40 return streq_ptr(target
->ifname
, link
->network
->dhcp_pd_uplink_name
) ||
41 strv_contains(target
->alternative_names
, link
->network
->dhcp_pd_uplink_name
);
43 if (link
->network
->dhcp_pd_uplink_index
> 0)
44 return target
->ifindex
== link
->network
->dhcp_pd_uplink_index
;
46 if (link
->network
->dhcp_pd_uplink_index
== UPLINK_INDEX_SELF
)
47 return link
== target
;
49 assert(link
->network
->dhcp_pd_uplink_index
== UPLINK_INDEX_AUTO
);
53 static void link_remove_dhcp_pd_subnet_prefix(Link
*link
, const struct in6_addr
*prefix
) {
57 assert(link
->manager
);
60 if (hashmap_get(link
->manager
->links_by_dhcp_pd_subnet_prefix
, prefix
) != link
)
63 hashmap_remove2(link
->manager
->links_by_dhcp_pd_subnet_prefix
, prefix
, &key
);
67 static int link_add_dhcp_pd_subnet_prefix(Link
*link
, const struct in6_addr
*prefix
) {
68 _cleanup_free_
struct in6_addr
*copy
= NULL
;
74 copy
= newdup(struct in6_addr
, prefix
, 1);
78 r
= hashmap_ensure_put(&link
->manager
->links_by_dhcp_pd_subnet_prefix
, &in6_addr_hash_ops_free
, copy
, link
);
87 static int link_get_by_dhcp_pd_subnet_prefix(Manager
*manager
, const struct in6_addr
*prefix
, Link
**ret
) {
93 link
= hashmap_get(manager
->links_by_dhcp_pd_subnet_prefix
, prefix
);
102 static int dhcp_pd_get_assigned_subnet_prefix(Link
*link
, const struct in6_addr
*pd_prefix
, uint8_t pd_prefix_len
, struct in6_addr
*ret
) {
104 assert(link
->manager
);
107 if (!link_dhcp_pd_is_enabled(link
))
110 if (link
->network
->dhcp_pd_assign
) {
113 SET_FOREACH(address
, link
->addresses
) {
114 if (address
->source
!= NETWORK_CONFIG_SOURCE_DHCP_PD
)
116 assert(address
->family
== AF_INET6
);
118 if (in6_addr_prefix_covers(pd_prefix
, pd_prefix_len
, &address
->in_addr
.in6
) <= 0)
122 struct in6_addr prefix
= address
->in_addr
.in6
;
124 in6_addr_mask(&prefix
, 64);
132 SET_FOREACH(route
, link
->manager
->routes
) {
133 if (route
->source
!= NETWORK_CONFIG_SOURCE_DHCP_PD
)
135 assert(route
->family
== AF_INET6
);
137 if (route
->nexthop
.ifindex
!= link
->ifindex
)
140 if (in6_addr_prefix_covers(pd_prefix
, pd_prefix_len
, &route
->dst
.in6
) > 0) {
142 *ret
= route
->dst
.in6
;
151 int dhcp_pd_remove(Link
*link
, bool only_marked
) {
155 assert(link
->manager
);
157 if (!link_dhcp_pd_is_enabled(link
))
161 link
->dhcp_pd_configured
= false;
163 if (!link
->network
->dhcp_pd_assign
) {
166 SET_FOREACH(route
, link
->manager
->routes
) {
167 if (route
->source
!= NETWORK_CONFIG_SOURCE_DHCP_PD
)
169 if (route
->nexthop
.ifindex
!= link
->ifindex
)
171 if (only_marked
&& !route_is_marked(route
))
175 sd_radv_remove_prefix(link
->radv
, &route
->dst
.in6
, 64);
177 link_remove_dhcp_pd_subnet_prefix(link
, &route
->dst
.in6
);
179 RET_GATHER(ret
, route_remove_and_cancel(route
, link
->manager
));
184 SET_FOREACH(address
, link
->addresses
) {
185 struct in6_addr prefix
;
187 if (address
->source
!= NETWORK_CONFIG_SOURCE_DHCP_PD
)
189 if (only_marked
&& !address_is_marked(address
))
192 prefix
= address
->in_addr
.in6
;
193 in6_addr_mask(&prefix
, 64);
196 sd_radv_remove_prefix(link
->radv
, &prefix
, 64);
198 link_remove_dhcp_pd_subnet_prefix(link
, &prefix
);
200 RET_GATHER(ret
, address_remove_and_cancel(address
, link
));
207 static int dhcp_pd_check_ready(Link
*link
);
209 static int dhcp_pd_address_ready_callback(Address
*address
) {
213 assert(address
->link
);
215 SET_FOREACH(a
, address
->link
->addresses
)
216 if (a
->source
== NETWORK_CONFIG_SOURCE_DHCP_PD
)
219 return dhcp_pd_check_ready(address
->link
);
222 static int dhcp_pd_check_ready(Link
*link
) {
226 assert(link
->network
);
228 if (link
->dhcp_pd_messages
> 0) {
229 log_link_debug(link
, "%s(): DHCP-PD addresses and routes are not set.", __func__
);
233 if (link
->network
->dhcp_pd_assign
) {
234 bool has_ready
= false;
237 SET_FOREACH(address
, link
->addresses
) {
238 if (address
->source
!= NETWORK_CONFIG_SOURCE_DHCP_PD
)
240 if (address_is_ready(address
)) {
247 SET_FOREACH(address
, link
->addresses
)
248 if (address
->source
== NETWORK_CONFIG_SOURCE_DHCP_PD
)
249 address
->callback
= dhcp_pd_address_ready_callback
;
251 log_link_debug(link
, "%s(): no DHCP-PD address is ready.", __func__
);
256 link
->dhcp_pd_configured
= true;
258 log_link_debug(link
, "DHCP-PD addresses and routes set.");
260 r
= dhcp_pd_remove(link
, /* only_marked = */ true);
264 link_check_ready(link
);
268 static int dhcp_pd_route_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
, Request
*req
, Link
*link
, Route
*route
) {
273 r
= route_configure_handler_internal(rtnl
, m
, link
, route
, "Failed to add prefix route for DHCP delegated subnet prefix");
277 r
= dhcp_pd_check_ready(link
);
279 link_enter_failed(link
);
284 static int dhcp_pd_request_route(Link
*link
, const struct in6_addr
*prefix
, usec_t lifetime_usec
) {
285 _cleanup_(route_unrefp
) Route
*route
= NULL
;
290 assert(link
->manager
);
291 assert(link
->network
);
294 if (link
->network
->dhcp_pd_assign
)
297 r
= route_new(&route
);
301 route
->source
= NETWORK_CONFIG_SOURCE_DHCP_PD
;
302 route
->family
= AF_INET6
;
303 route
->dst
.in6
= *prefix
;
304 route
->dst_prefixlen
= 64;
305 route
->protocol
= RTPROT_DHCP
;
306 route
->priority
= link
->network
->dhcp_pd_route_metric
;
307 route
->lifetime_usec
= lifetime_usec
;
309 r
= route_adjust_nexthops(route
, link
);
313 if (route_get(link
->manager
, route
, &existing
) < 0)
314 link
->dhcp_pd_configured
= false;
316 route_unmark(existing
);
318 r
= link_request_route(link
, route
, &link
->dhcp_pd_messages
, dhcp_pd_route_handler
);
320 return log_link_error_errno(link
, r
, "Failed to request DHCP-PD prefix route: %m");
325 static int dhcp_pd_address_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
, Request
*req
, Link
*link
, Address
*address
) {
330 r
= address_configure_handler_internal(rtnl
, m
, link
, "Could not set DHCP-PD address");
334 r
= dhcp_pd_check_ready(link
);
336 link_enter_failed(link
);
341 static void log_dhcp_pd_address(Link
*link
, const Address
*address
) {
343 assert(address
->family
== AF_INET6
);
345 int log_level
= address_get_harder(link
, address
, NULL
) >= 0 ? LOG_DEBUG
: LOG_INFO
;
347 if (log_level
< log_get_max_level())
350 log_link_full(link
, log_level
, "DHCP-PD address %s (valid %s, preferred %s)",
351 IN6_ADDR_PREFIX_TO_STRING(&address
->in_addr
.in6
, address
->prefixlen
),
352 FORMAT_LIFETIME(address
->lifetime_valid_usec
),
353 FORMAT_LIFETIME(address
->lifetime_preferred_usec
));
356 static int dhcp_pd_request_address_one(Address
*address
, Link
*link
) {
362 log_dhcp_pd_address(link
, address
);
364 if (address_get(link
, address
, &existing
) < 0)
365 link
->dhcp_pd_configured
= false;
367 address_unmark(existing
);
369 return link_request_address(link
, address
, &link
->dhcp_pd_messages
, dhcp_pd_address_handler
, NULL
);
372 int dhcp_pd_reconfigure_address(Address
*address
, Link
*link
) {
376 assert(address
->source
== NETWORK_CONFIG_SOURCE_DHCP_PD
);
379 r
= regenerate_address(address
, link
);
383 r
= dhcp_pd_request_address_one(address
, link
);
387 if (!link
->dhcp_pd_configured
)
388 link_set_state(link
, LINK_STATE_CONFIGURING
);
390 link_check_ready(link
);
394 static int dhcp_pd_request_address(
396 const struct in6_addr
*prefix
,
397 usec_t lifetime_preferred_usec
,
398 usec_t lifetime_valid_usec
) {
403 assert(link
->network
);
406 if (!link
->network
->dhcp_pd_assign
)
409 _cleanup_hashmap_free_ Hashmap
*tokens_by_address
= NULL
;
410 r
= dhcp_pd_generate_addresses(link
, prefix
, &tokens_by_address
);
412 return log_link_warning_errno(link
, r
, "Failed to generate addresses for acquired DHCP delegated prefix: %m");
416 HASHMAP_FOREACH_KEY(token
, a
, tokens_by_address
) {
417 _cleanup_(address_unrefp
) Address
*address
= NULL
;
419 r
= address_new(&address
);
421 return log_link_error_errno(link
, r
, "Failed to allocate address for DHCP delegated prefix: %m");
423 address
->source
= NETWORK_CONFIG_SOURCE_DHCP_PD
;
424 address
->family
= AF_INET6
;
425 address
->in_addr
.in6
= *a
;
426 address
->prefixlen
= 64;
427 address
->lifetime_preferred_usec
= lifetime_preferred_usec
;
428 address
->lifetime_valid_usec
= lifetime_valid_usec
;
429 SET_FLAG(address
->flags
, IFA_F_MANAGETEMPADDR
, link
->network
->dhcp_pd_manage_temporary_address
);
430 address
->route_metric
= link
->network
->dhcp_pd_route_metric
;
431 address
->token
= ipv6_token_ref(token
);
433 r
= free_and_strdup_warn(&address
->netlabel
, link
->network
->dhcp_pd_netlabel
);
437 r
= dhcp_pd_request_address_one(address
, link
);
439 return log_link_error_errno(link
, r
, "Failed to request DHCP delegated prefix address: %m");
445 static int dhcp_pd_calculate_subnet_prefix(
446 const struct in6_addr
*pd_prefix
,
447 uint8_t pd_prefix_len
,
449 struct in6_addr
*ret
) {
451 struct in6_addr prefix
;
454 assert(pd_prefix_len
<= 64);
457 if (subnet_id
>= UINT64_C(1) << (64 - pd_prefix_len
))
462 if (pd_prefix_len
< 32)
463 prefix
.s6_addr32
[0] |= htobe32(subnet_id
>> 32);
465 prefix
.s6_addr32
[1] |= htobe32(subnet_id
& 0xffffffff);
471 static int dhcp_pd_get_preferred_subnet_prefix(
473 const struct in6_addr
*pd_prefix
,
474 uint8_t pd_prefix_len
,
475 struct in6_addr
*ret
) {
477 struct in6_addr prefix
;
482 assert(link
->manager
);
483 assert(link
->network
);
486 if (link
->network
->dhcp_pd_subnet_id
>= 0) {
487 /* If the link has a preference for a particular subnet id try to allocate that */
489 r
= dhcp_pd_calculate_subnet_prefix(pd_prefix
, pd_prefix_len
, link
->network
->dhcp_pd_subnet_id
, &prefix
);
491 return log_link_warning_errno(link
, r
,
492 "subnet id %" PRIi64
" is out of range. Only have %" PRIu64
" subnets.",
493 link
->network
->dhcp_pd_subnet_id
, UINT64_C(1) << (64 - pd_prefix_len
));
499 if (dhcp_pd_get_assigned_subnet_prefix(link
, pd_prefix
, pd_prefix_len
, ret
) >= 0)
502 for (uint64_t n
= 0; ; n
++) {
503 /* If we do not have an allocation preference just iterate
504 * through the address space and return the first free prefix. */
506 r
= dhcp_pd_calculate_subnet_prefix(pd_prefix
, pd_prefix_len
, n
, &prefix
);
508 return log_link_warning_errno(link
, r
,
509 "Couldn't find a suitable prefix. Ran out of address space.");
511 /* Do not use explicitly requested subnet IDs. Note that the corresponding link may not
512 * appear yet. So, we need to check the ID is not used in any .network files. */
513 if (set_contains(link
->manager
->dhcp_pd_subnet_ids
, &n
))
516 /* Check that the prefix is not assigned to another link. */
517 if (link_get_by_dhcp_pd_subnet_prefix(link
->manager
, &prefix
, &assigned_link
) < 0 ||
518 assigned_link
== link
)
522 r
= link_add_dhcp_pd_subnet_prefix(link
, &prefix
);
524 return log_link_warning_errno(link
, r
, "Failed to save acquired free subnet prefix: %m");
530 static int dhcp_pd_assign_subnet_prefix(
532 const struct in6_addr
*pd_prefix
,
533 uint8_t pd_prefix_len
,
534 usec_t lifetime_preferred_usec
,
535 usec_t lifetime_valid_usec
,
538 struct in6_addr prefix
;
542 assert(link
->network
);
545 r
= dhcp_pd_get_preferred_subnet_prefix(link
, pd_prefix
, pd_prefix_len
, &prefix
);
547 return r
== -ERANGE
? 0 : r
;
549 const char *pretty
= IN6_ADDR_PREFIX_TO_STRING(&prefix
, 64);
551 if (link_radv_enabled(link
) && link
->network
->dhcp_pd_announce
) {
553 log_link_debug(link
, "Ignoring Announce= setting on upstream interface.");
555 r
= radv_add_prefix(link
, &prefix
, 64, lifetime_preferred_usec
, lifetime_valid_usec
);
557 return log_link_warning_errno(link
, r
,
558 "Failed to assign/update prefix %s to IPv6 Router Advertisement: %m",
563 r
= dhcp_pd_request_route(link
, &prefix
, lifetime_valid_usec
);
565 return log_link_warning_errno(link
, r
,
566 "Failed to assign/update route for prefix %s: %m", pretty
);
568 r
= dhcp_pd_request_address(link
, &prefix
, lifetime_preferred_usec
, lifetime_valid_usec
);
570 return log_link_warning_errno(link
, r
,
571 "Failed to assign/update address for prefix %s: %m", pretty
);
573 log_link_debug(link
, "Assigned prefix %s", pretty
);
577 static int dhcp_pd_prepare(Link
*link
) {
578 if (!IN_SET(link
->state
, LINK_STATE_CONFIGURING
, LINK_STATE_CONFIGURED
))
581 if (!link_dhcp_pd_is_enabled(link
))
584 if (link_radv_enabled(link
) && link
->network
->dhcp_pd_announce
&& !link
->radv
)
587 link_mark_addresses(link
, NETWORK_CONFIG_SOURCE_DHCP_PD
);
588 manager_mark_routes(link
->manager
, link
, NETWORK_CONFIG_SOURCE_DHCP_PD
);
593 static int dhcp_pd_finalize(Link
*link
) {
596 if (!IN_SET(link
->state
, LINK_STATE_CONFIGURING
, LINK_STATE_CONFIGURED
))
599 if (link
->dhcp_pd_messages
== 0) {
600 link
->dhcp_pd_configured
= false;
602 r
= dhcp_pd_remove(link
, /* only_marked = */ true);
607 if (!link
->dhcp_pd_configured
)
608 link_set_state(link
, LINK_STATE_CONFIGURING
);
610 link_check_ready(link
);
614 void dhcp_pd_prefix_lost(Link
*uplink
) {
620 assert(uplink
->manager
);
622 HASHMAP_FOREACH(link
, uplink
->manager
->links_by_index
) {
623 if (!dhcp_pd_is_uplink(link
, uplink
, /* accept_auto = */ true))
626 r
= dhcp_pd_remove(link
, /* only_marked = */ false);
628 link_enter_failed(link
);
631 SET_FOREACH(route
, uplink
->manager
->routes
) {
632 if (!IN_SET(route
->source
, NETWORK_CONFIG_SOURCE_DHCP4
, NETWORK_CONFIG_SOURCE_DHCP6
))
634 if (route
->family
!= AF_INET6
)
636 if (route
->type
!= RTN_UNREACHABLE
)
638 if (!set_contains(uplink
->dhcp_pd_prefixes
,
639 &(struct in_addr_prefix
) {
641 .prefixlen
= route
->dst_prefixlen
,
642 .address
= route
->dst
}))
645 (void) route_remove_and_cancel(route
, uplink
->manager
);
648 set_clear(uplink
->dhcp_pd_prefixes
);
651 void dhcp4_pd_prefix_lost(Link
*uplink
) {
654 dhcp_pd_prefix_lost(uplink
);
656 if (uplink
->dhcp4_6rd_tunnel_name
&&
657 link_get_by_name(uplink
->manager
, uplink
->dhcp4_6rd_tunnel_name
, &tunnel
) >= 0)
658 (void) link_remove(tunnel
);
661 static int dhcp4_unreachable_route_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
, Request
*req
, Link
*link
, Route
*route
) {
666 r
= route_configure_handler_internal(rtnl
, m
, link
, route
, "Failed to set unreachable route for DHCPv4 delegated prefix");
670 r
= dhcp4_check_ready(link
);
672 link_enter_failed(link
);
677 static int dhcp6_unreachable_route_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
, Request
*req
, Link
*link
, Route
*route
) {
682 r
= route_configure_handler_internal(rtnl
, m
, link
, route
, "Failed to set unreachable route for DHCPv6 delegated prefix");
686 r
= dhcp6_check_ready(link
);
688 link_enter_failed(link
);
693 static int dhcp_request_unreachable_route(
695 const struct in6_addr
*addr
,
697 usec_t lifetime_usec
,
698 NetworkConfigSource source
,
699 const union in_addr_union
*server_address
,
701 route_netlink_handler_t callback
,
704 _cleanup_(route_unrefp
) Route
*route
= NULL
;
709 assert(link
->manager
);
711 assert(IN_SET(source
, NETWORK_CONFIG_SOURCE_DHCP4
, NETWORK_CONFIG_SOURCE_DHCP6
));
712 assert(server_address
);
717 if (prefixlen
>= 64) {
718 log_link_debug(link
, "Not adding a blocking route for DHCP delegated prefix %s since the prefix has length >= 64.",
719 IN6_ADDR_PREFIX_TO_STRING(addr
, prefixlen
));
723 r
= route_new(&route
);
727 route
->source
= source
;
728 route
->provider
= *server_address
;
729 route
->family
= AF_INET6
;
730 route
->dst
.in6
= *addr
;
731 route
->dst_prefixlen
= prefixlen
;
732 route
->type
= RTN_UNREACHABLE
;
733 route
->protocol
= RTPROT_DHCP
;
734 route
->priority
= IP6_RT_PRIO_USER
;
735 route
->lifetime_usec
= lifetime_usec
;
737 r
= route_adjust_nexthops(route
, link
);
741 if (route_get(link
->manager
, route
, &existing
) < 0)
744 route_unmark(existing
);
746 r
= link_request_route(link
, route
, counter
, callback
);
748 return log_link_error_errno(link
, r
, "Failed to request unreachable route for DHCP delegated prefix %s: %m",
749 IN6_ADDR_PREFIX_TO_STRING(addr
, prefixlen
));
754 static int dhcp4_request_unreachable_route(
756 const struct in6_addr
*addr
,
758 usec_t lifetime_usec
,
759 const union in_addr_union
*server_address
) {
761 return dhcp_request_unreachable_route(link
, addr
, prefixlen
, lifetime_usec
,
762 NETWORK_CONFIG_SOURCE_DHCP4
, server_address
,
763 &link
->dhcp4_messages
, dhcp4_unreachable_route_handler
,
764 &link
->dhcp4_configured
);
767 static int dhcp6_request_unreachable_route(
769 const struct in6_addr
*addr
,
771 usec_t lifetime_usec
,
772 const union in_addr_union
*server_address
) {
774 return dhcp_request_unreachable_route(link
, addr
, prefixlen
, lifetime_usec
,
775 NETWORK_CONFIG_SOURCE_DHCP6
, server_address
,
776 &link
->dhcp6_messages
, dhcp6_unreachable_route_handler
,
777 &link
->dhcp6_configured
);
780 static int dhcp_pd_prefix_add(Link
*link
, const struct in6_addr
*prefix
, uint8_t prefixlen
) {
781 struct in_addr_prefix
*p
;
787 p
= new(struct in_addr_prefix
, 1);
791 *p
= (struct in_addr_prefix
) {
793 .prefixlen
= prefixlen
,
794 .address
.in6
= *prefix
,
797 int log_level
= set_contains(link
->dhcp_pd_prefixes
, p
) ? LOG_DEBUG
:
798 prefixlen
> 64 || prefixlen
< 48 ? LOG_WARNING
: LOG_INFO
;
801 "DHCP: received delegated prefix %s%s",
802 IN6_ADDR_PREFIX_TO_STRING(prefix
, prefixlen
),
803 prefixlen
> 64 ? " with prefix length > 64, ignoring." :
804 prefixlen
< 48 ? " with prefix length < 48, looks unusual.": "");
806 /* Store PD prefix even if prefixlen > 64, not to make logged at warning level so frequently. */
807 r
= set_ensure_consume(&link
->dhcp_pd_prefixes
, &in_addr_prefix_hash_ops_free
, p
);
809 return log_link_error_errno(link
, r
, "Failed to store DHCP delegated prefix %s: %m",
810 IN6_ADDR_PREFIX_TO_STRING(prefix
, prefixlen
));
814 static int dhcp4_pd_request_default_gateway_on_6rd_tunnel(Link
*link
, const struct in_addr
*br_address
, usec_t lifetime_usec
) {
815 _cleanup_(route_unrefp
) Route
*route
= NULL
;
820 assert(link
->manager
);
823 r
= route_new(&route
);
825 return log_link_debug_errno(link
, r
, "Failed to allocate default gateway for DHCP delegated prefix: %m");
827 route
->source
= NETWORK_CONFIG_SOURCE_DHCP_PD
;
828 route
->family
= AF_INET6
;
829 route
->nexthop
.family
= AF_INET6
;
830 route
->nexthop
.gw
.in6
.s6_addr32
[3] = br_address
->s_addr
;
831 route
->scope
= RT_SCOPE_UNIVERSE
;
832 route
->protocol
= RTPROT_DHCP
;
833 route
->priority
= IP6_RT_PRIO_USER
;
834 route
->lifetime_usec
= lifetime_usec
;
836 r
= route_adjust_nexthops(route
, link
);
840 if (route_get(link
->manager
, route
, &existing
) < 0) /* This is a new route. */
841 link
->dhcp_pd_configured
= false;
843 route_unmark(existing
);
845 r
= link_request_route(link
, route
, &link
->dhcp_pd_messages
, dhcp_pd_route_handler
);
847 return log_link_debug_errno(link
, r
, "Failed to request default gateway for DHCP delegated prefix: %m");
852 static void dhcp4_calculate_pd_prefix(
853 const struct in_addr
*ipv4address
,
855 const struct in6_addr
*sixrd_prefix
,
856 uint8_t sixrd_prefixlen
,
857 struct in6_addr
*ret_pd_prefix
,
858 uint8_t *ret_pd_prefixlen
) {
860 struct in6_addr pd_prefix
;
863 assert(ipv4masklen
<= 32);
864 assert(sixrd_prefix
);
865 assert(32 - ipv4masklen
+ sixrd_prefixlen
<= 128);
866 assert(ret_pd_prefix
);
868 pd_prefix
= *sixrd_prefix
;
869 for (unsigned i
= 0; i
< (unsigned) (32 - ipv4masklen
); i
++)
870 if (ipv4address
->s_addr
& htobe32(UINT32_C(1) << (32 - ipv4masklen
- i
- 1)))
871 pd_prefix
.s6_addr
[(i
+ sixrd_prefixlen
) / 8] |= 1 << (7 - (i
+ sixrd_prefixlen
) % 8);
873 *ret_pd_prefix
= pd_prefix
;
874 if (ret_pd_prefixlen
)
875 *ret_pd_prefixlen
= 32 - ipv4masklen
+ sixrd_prefixlen
;
878 static int dhcp4_pd_assign_subnet_prefix(Link
*link
, Link
*uplink
) {
879 uint8_t ipv4masklen
, sixrd_prefixlen
, pd_prefixlen
;
880 struct in6_addr sixrd_prefix
, pd_prefix
;
881 const struct in_addr
*br_addresses
;
882 struct in_addr ipv4address
;
883 usec_t lifetime_usec
;
888 assert(uplink
->manager
);
889 assert(uplink
->dhcp_lease
);
891 r
= sd_dhcp_lease_get_address(uplink
->dhcp_lease
, &ipv4address
);
893 return log_link_warning_errno(uplink
, r
, "Failed to get DHCPv4 address: %m");
895 r
= sd_dhcp_lease_get_lifetime_timestamp(uplink
->dhcp_lease
, CLOCK_BOOTTIME
, &lifetime_usec
);
897 return log_link_warning_errno(uplink
, r
, "Failed to get lifetime of DHCPv4 lease: %m");
899 r
= sd_dhcp_lease_get_6rd(uplink
->dhcp_lease
, &ipv4masklen
, &sixrd_prefixlen
, &sixrd_prefix
, &br_addresses
, NULL
);
901 return log_link_warning_errno(uplink
, r
, "Failed to get DHCPv4 6rd option: %m");
903 dhcp4_calculate_pd_prefix(&ipv4address
, ipv4masklen
, &sixrd_prefix
, sixrd_prefixlen
, &pd_prefix
, &pd_prefixlen
);
905 if (pd_prefixlen
> 64)
908 r
= dhcp_pd_prepare(link
);
912 if (streq_ptr(uplink
->dhcp4_6rd_tunnel_name
, link
->ifname
)) {
913 r
= dhcp4_pd_request_default_gateway_on_6rd_tunnel(link
, &br_addresses
[0], lifetime_usec
);
918 r
= dhcp_pd_assign_subnet_prefix(link
, &pd_prefix
, pd_prefixlen
, lifetime_usec
, lifetime_usec
, /* is_uplink = */ false);
922 return dhcp_pd_finalize(link
);
925 static int dhcp4_pd_6rd_tunnel_create_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
, Link
*link
) {
930 assert(link
->manager
);
931 assert(link
->dhcp4_6rd_tunnel_name
);
933 if (IN_SET(link
->state
, LINK_STATE_FAILED
, LINK_STATE_LINGER
))
936 r
= sd_netlink_message_get_errno(m
);
938 log_link_message_warning_errno(link
, m
, r
, "Failed to create tunnel device for DHCPv4 6rd");
939 link_enter_failed(link
);
946 int dhcp4_pd_prefix_acquired(Link
*uplink
) {
947 _cleanup_free_
char *tunnel_name
= NULL
;
948 uint8_t ipv4masklen
, sixrd_prefixlen
, pd_prefixlen
;
949 struct in6_addr sixrd_prefix
, pd_prefix
;
950 struct in_addr ipv4address
;
951 union in_addr_union server_address
;
952 const struct in_addr
*br_addresses
;
953 usec_t lifetime_usec
;
958 assert(uplink
->manager
);
959 assert(uplink
->dhcp_lease
);
961 r
= sd_dhcp_lease_get_address(uplink
->dhcp_lease
, &ipv4address
);
963 return log_link_warning_errno(uplink
, r
, "Failed to get DHCPv4 address: %m");
965 r
= sd_dhcp_lease_get_lifetime_timestamp(uplink
->dhcp_lease
, CLOCK_BOOTTIME
, &lifetime_usec
);
967 return log_link_warning_errno(uplink
, r
, "Failed to get lifetime of DHCPv4 lease: %m");
969 r
= sd_dhcp_lease_get_server_identifier(uplink
->dhcp_lease
, &server_address
.in
);
971 return log_link_warning_errno(uplink
, r
, "Failed to get server address of DHCPv4 lease: %m");
973 r
= sd_dhcp_lease_get_6rd(uplink
->dhcp_lease
, &ipv4masklen
, &sixrd_prefixlen
, &sixrd_prefix
, &br_addresses
, NULL
);
975 return log_link_warning_errno(uplink
, r
, "Failed to get DHCPv4 6rd option: %m");
978 log_link_debug(uplink
, "DHCPv4: 6rd option is acquired: IPv4_masklen=%u, 6rd_prefix=%s, br_address="IPV4_ADDRESS_FMT_STR
,
980 IN6_ADDR_PREFIX_TO_STRING(&sixrd_prefix
, sixrd_prefixlen
),
981 IPV4_ADDRESS_FMT_VAL(*br_addresses
));
983 /* Calculate PD prefix */
984 dhcp4_calculate_pd_prefix(&ipv4address
, ipv4masklen
, &sixrd_prefix
, sixrd_prefixlen
, &pd_prefix
, &pd_prefixlen
);
986 /* Register and log PD prefix */
987 r
= dhcp_pd_prefix_add(uplink
, &pd_prefix
, pd_prefixlen
);
991 /* Request unreachable route */
992 r
= dhcp4_request_unreachable_route(uplink
, &pd_prefix
, pd_prefixlen
, lifetime_usec
, &server_address
);
996 /* Generate 6rd SIT tunnel device name. */
997 r
= dhcp4_pd_create_6rd_tunnel_name(uplink
, &tunnel_name
);
1001 /* Remove old tunnel device if exists. */
1002 if (!streq_ptr(uplink
->dhcp4_6rd_tunnel_name
, tunnel_name
)) {
1005 if (uplink
->dhcp4_6rd_tunnel_name
&&
1006 link_get_by_name(uplink
->manager
, uplink
->dhcp4_6rd_tunnel_name
, &old_tunnel
) >= 0)
1007 (void) link_remove(old_tunnel
);
1009 free_and_replace(uplink
->dhcp4_6rd_tunnel_name
, tunnel_name
);
1012 /* Create 6rd SIT tunnel device if it does not exist yet. */
1013 if (link_get_by_name(uplink
->manager
, uplink
->dhcp4_6rd_tunnel_name
, NULL
) < 0) {
1014 r
= dhcp4_pd_create_6rd_tunnel(uplink
, dhcp4_pd_6rd_tunnel_create_handler
);
1019 /* Then, assign subnet prefixes to downstream interfaces. */
1020 HASHMAP_FOREACH(link
, uplink
->manager
->links_by_index
) {
1021 if (!dhcp_pd_is_uplink(link
, uplink
, /* accept_auto = */ true))
1024 r
= dhcp4_pd_assign_subnet_prefix(link
, uplink
);
1026 /* When failed on the upstream interface (i.e., the case link == uplink),
1027 * immediately abort the assignment of the prefixes. As, the all assigned
1028 * prefixes will be dropped soon in link_enter_failed(), and it is meaningless
1029 * to continue the assignment. */
1033 link_enter_failed(link
);
1040 static int dhcp6_pd_assign_subnet_prefixes(Link
*link
, Link
*uplink
) {
1045 assert(uplink
->dhcp6_lease
);
1047 r
= dhcp_pd_prepare(link
);
1051 FOREACH_DHCP6_PD_PREFIX(uplink
->dhcp6_lease
) {
1052 usec_t lifetime_preferred_usec
, lifetime_valid_usec
;
1053 struct in6_addr pd_prefix
;
1054 uint8_t pd_prefix_len
;
1056 r
= sd_dhcp6_lease_get_pd_prefix(uplink
->dhcp6_lease
, &pd_prefix
, &pd_prefix_len
);
1060 if (pd_prefix_len
> 64)
1063 /* Mask prefix for safety. */
1064 r
= in6_addr_mask(&pd_prefix
, pd_prefix_len
);
1068 r
= sd_dhcp6_lease_get_pd_lifetime_timestamp(uplink
->dhcp6_lease
, CLOCK_BOOTTIME
,
1069 &lifetime_preferred_usec
, &lifetime_valid_usec
);
1073 r
= dhcp_pd_assign_subnet_prefix(link
, &pd_prefix
, pd_prefix_len
,
1074 lifetime_preferred_usec
, lifetime_valid_usec
,
1075 /* is_uplink = */ link
== uplink
);
1080 return dhcp_pd_finalize(link
);
1083 int dhcp6_pd_prefix_acquired(Link
*uplink
) {
1084 union in_addr_union server_address
;
1089 assert(uplink
->dhcp6_lease
);
1091 r
= sd_dhcp6_lease_get_server_address(uplink
->dhcp6_lease
, &server_address
.in6
);
1093 return log_link_warning_errno(uplink
, r
, "Failed to get server address of DHCPv6 lease: %m");
1095 /* First, logs acquired prefixes and request unreachable routes. */
1096 FOREACH_DHCP6_PD_PREFIX(uplink
->dhcp6_lease
) {
1097 usec_t lifetime_valid_usec
;
1098 struct in6_addr pd_prefix
;
1099 uint8_t pd_prefix_len
;
1101 r
= sd_dhcp6_lease_get_pd_prefix(uplink
->dhcp6_lease
, &pd_prefix
, &pd_prefix_len
);
1105 /* Mask prefix for safety. */
1106 r
= in6_addr_mask(&pd_prefix
, pd_prefix_len
);
1108 return log_link_error_errno(uplink
, r
, "Failed to mask DHCPv6 delegated prefix: %m");
1110 r
= dhcp_pd_prefix_add(uplink
, &pd_prefix
, pd_prefix_len
);
1114 r
= sd_dhcp6_lease_get_pd_lifetime_timestamp(uplink
->dhcp6_lease
, CLOCK_BOOTTIME
,
1115 NULL
, &lifetime_valid_usec
);
1119 r
= dhcp6_request_unreachable_route(uplink
, &pd_prefix
, pd_prefix_len
,
1120 lifetime_valid_usec
, &server_address
);
1125 /* Then, assign subnet prefixes. */
1126 HASHMAP_FOREACH(link
, uplink
->manager
->links_by_index
) {
1127 if (!dhcp_pd_is_uplink(link
, uplink
, /* accept_auto = */ true))
1130 r
= dhcp6_pd_assign_subnet_prefixes(link
, uplink
);
1132 /* When failed on the upstream interface (i.e., the case link == uplink),
1133 * immediately abort the assignment of the prefixes. As, the all assigned
1134 * prefixes will be dropped soon in link_enter_failed(), and it is meaningless
1135 * to continue the assignment. */
1139 link_enter_failed(link
);
1146 static bool dhcp4_pd_uplink_is_ready(Link
*link
) {
1152 if (!link
->network
->dhcp_use_6rd
)
1155 if (!IN_SET(link
->state
, LINK_STATE_CONFIGURING
, LINK_STATE_CONFIGURED
))
1158 if (!link
->dhcp_client
)
1161 if (sd_dhcp_client_is_running(link
->dhcp_client
) <= 0)
1164 return sd_dhcp_lease_has_6rd(link
->dhcp_lease
);
1167 static bool dhcp6_pd_uplink_is_ready(Link
*link
) {
1173 if (!link
->network
->dhcp6_use_pd_prefix
)
1176 if (!IN_SET(link
->state
, LINK_STATE_CONFIGURING
, LINK_STATE_CONFIGURED
))
1179 if (!link
->dhcp6_client
)
1182 if (sd_dhcp6_client_is_running(link
->dhcp6_client
) <= 0)
1185 return sd_dhcp6_lease_has_pd_prefix(link
->dhcp6_lease
);
1188 int dhcp_pd_find_uplink(Link
*link
, Link
**ret
) {
1189 Link
*uplink
= NULL
;
1193 assert(link
->manager
);
1194 assert(link_dhcp_pd_is_enabled(link
));
1197 if (link
->network
->dhcp_pd_uplink_name
)
1198 r
= link_get_by_name(link
->manager
, link
->network
->dhcp_pd_uplink_name
, &uplink
);
1199 else if (link
->network
->dhcp_pd_uplink_index
> 0)
1200 r
= link_get_by_index(link
->manager
, link
->network
->dhcp_pd_uplink_index
, &uplink
);
1201 else if (link
->network
->dhcp_pd_uplink_index
== UPLINK_INDEX_SELF
)
1207 if (dhcp4_pd_uplink_is_ready(uplink
)) {
1212 if (dhcp6_pd_uplink_is_ready(uplink
)) {
1220 HASHMAP_FOREACH(uplink
, link
->manager
->links_by_index
) {
1221 /* Assume that there exists at most one link which acquired delegated prefixes. */
1222 if (dhcp4_pd_uplink_is_ready(uplink
)) {
1227 if (dhcp6_pd_uplink_is_ready(uplink
)) {
1236 int dhcp_request_prefix_delegation(Link
*link
) {
1242 if (!link_dhcp_pd_is_enabled(link
))
1245 r
= dhcp_pd_find_uplink(link
, &uplink
);
1249 log_link_debug(link
, "Requesting subnets of delegated prefixes acquired by DHCPv%c client on %s",
1250 r
== AF_INET
? '4' : '6', uplink
->ifname
);
1252 return r
== AF_INET
?
1253 dhcp4_pd_assign_subnet_prefix(link
, uplink
) :
1254 dhcp6_pd_assign_subnet_prefixes(link
, uplink
);
1257 int config_parse_dhcp_pd_subnet_id(
1259 const char *filename
,
1261 const char *section
,
1262 unsigned section_line
,
1269 int64_t *p
= ASSERT_PTR(data
);
1277 if (isempty(rvalue
) || streq(rvalue
, "auto")) {
1282 r
= safe_atoux64(rvalue
, &t
);
1284 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1285 "Failed to parse %s=, ignoring assignment: %s",
1289 if (t
> INT64_MAX
) {
1290 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
1291 "Invalid subnet id '%s', ignoring assignment.",