1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
3 #include <linux/ipv6_route.h>
4 #include <linux/rtnetlink.h>
6 #include "sd-dhcp-client.h"
7 #include "sd-dhcp6-client.h"
8 #include "sd-netlink.h"
11 #include "dhcp6-lease-internal.h"
12 #include "errno-util.h"
14 #include "in-addr-prefix-util.h"
15 #include "networkd-address.h"
16 #include "networkd-address-generation.h"
17 #include "networkd-dhcp-prefix-delegation.h"
18 #include "networkd-dhcp6.h"
19 #include "networkd-link.h"
20 #include "networkd-manager.h"
21 #include "networkd-queue.h"
22 #include "networkd-radv.h"
23 #include "networkd-route.h"
24 #include "networkd-route-util.h"
25 #include "networkd-setlink.h"
26 #include "parse-util.h"
28 #include "string-util.h"
32 bool link_dhcp_pd_is_enabled(Link
*link
) {
38 return link
->network
->dhcp_pd
;
41 bool dhcp_pd_is_uplink(Link
*link
, Link
*target
, bool accept_auto
) {
45 if (!link_dhcp_pd_is_enabled(link
))
48 if (link
->network
->dhcp_pd_uplink_name
)
49 return streq_ptr(target
->ifname
, link
->network
->dhcp_pd_uplink_name
) ||
50 strv_contains(target
->alternative_names
, link
->network
->dhcp_pd_uplink_name
);
52 if (link
->network
->dhcp_pd_uplink_index
> 0)
53 return target
->ifindex
== link
->network
->dhcp_pd_uplink_index
;
55 if (link
->network
->dhcp_pd_uplink_index
== UPLINK_INDEX_SELF
)
56 return link
== target
;
58 assert(link
->network
->dhcp_pd_uplink_index
== UPLINK_INDEX_AUTO
);
62 static void link_remove_dhcp_pd_subnet_prefix(Link
*link
, const struct in6_addr
*prefix
) {
66 assert(link
->manager
);
69 if (hashmap_get(link
->manager
->links_by_dhcp_pd_subnet_prefix
, prefix
) != link
)
72 hashmap_remove2(link
->manager
->links_by_dhcp_pd_subnet_prefix
, prefix
, &key
);
76 static int link_add_dhcp_pd_subnet_prefix(Link
*link
, const struct in6_addr
*prefix
) {
77 _cleanup_free_
struct in6_addr
*copy
= NULL
;
83 copy
= newdup(struct in6_addr
, prefix
, 1);
87 r
= hashmap_ensure_put(&link
->manager
->links_by_dhcp_pd_subnet_prefix
, &in6_addr_hash_ops_free
, copy
, link
);
96 static int link_get_by_dhcp_pd_subnet_prefix(Manager
*manager
, const struct in6_addr
*prefix
, Link
**ret
) {
102 link
= hashmap_get(manager
->links_by_dhcp_pd_subnet_prefix
, prefix
);
111 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
) {
113 assert(link
->manager
);
116 if (!link_dhcp_pd_is_enabled(link
))
119 if (link
->network
->dhcp_pd_assign
) {
122 SET_FOREACH(address
, link
->addresses
) {
123 if (address
->source
!= NETWORK_CONFIG_SOURCE_DHCP_PD
)
125 assert(address
->family
== AF_INET6
);
127 if (in6_addr_prefix_covers(pd_prefix
, pd_prefix_len
, &address
->in_addr
.in6
) <= 0)
131 struct in6_addr prefix
= address
->in_addr
.in6
;
133 in6_addr_mask(&prefix
, 64);
141 SET_FOREACH(route
, link
->manager
->routes
) {
142 if (route
->source
!= NETWORK_CONFIG_SOURCE_DHCP_PD
)
144 assert(route
->family
== AF_INET6
);
146 if (route
->nexthop
.ifindex
!= link
->ifindex
)
149 if (in6_addr_prefix_covers(pd_prefix
, pd_prefix_len
, &route
->dst
.in6
) > 0) {
151 *ret
= route
->dst
.in6
;
160 int dhcp_pd_remove(Link
*link
, bool only_marked
) {
164 assert(link
->manager
);
166 if (!link_dhcp_pd_is_enabled(link
))
170 link
->dhcp_pd_configured
= false;
172 if (!link
->network
->dhcp_pd_assign
) {
175 SET_FOREACH(route
, link
->manager
->routes
) {
176 if (route
->source
!= NETWORK_CONFIG_SOURCE_DHCP_PD
)
178 if (route
->nexthop
.ifindex
!= link
->ifindex
)
180 if (only_marked
&& !route_is_marked(route
))
184 sd_radv_remove_prefix(link
->radv
, &route
->dst
.in6
, 64);
186 link_remove_dhcp_pd_subnet_prefix(link
, &route
->dst
.in6
);
188 RET_GATHER(ret
, route_remove_and_cancel(route
, link
->manager
));
193 SET_FOREACH(address
, link
->addresses
) {
194 struct in6_addr prefix
;
196 if (address
->source
!= NETWORK_CONFIG_SOURCE_DHCP_PD
)
198 if (only_marked
&& !address_is_marked(address
))
201 prefix
= address
->in_addr
.in6
;
202 in6_addr_mask(&prefix
, 64);
205 sd_radv_remove_prefix(link
->radv
, &prefix
, 64);
207 link_remove_dhcp_pd_subnet_prefix(link
, &prefix
);
209 RET_GATHER(ret
, address_remove_and_cancel(address
, link
));
216 static int dhcp_pd_check_ready(Link
*link
);
218 static int dhcp_pd_address_ready_callback(Address
*address
) {
222 assert(address
->link
);
224 SET_FOREACH(a
, address
->link
->addresses
)
225 if (a
->source
== NETWORK_CONFIG_SOURCE_DHCP_PD
)
228 return dhcp_pd_check_ready(address
->link
);
231 static int dhcp_pd_check_ready(Link
*link
) {
235 assert(link
->network
);
237 if (link
->dhcp_pd_messages
> 0) {
238 log_link_debug(link
, "%s(): DHCP-PD addresses and routes are not set.", __func__
);
242 if (link
->network
->dhcp_pd_assign
) {
243 bool has_ready
= false;
246 SET_FOREACH(address
, link
->addresses
) {
247 if (address
->source
!= NETWORK_CONFIG_SOURCE_DHCP_PD
)
249 if (address_is_ready(address
)) {
256 SET_FOREACH(address
, link
->addresses
)
257 if (address
->source
== NETWORK_CONFIG_SOURCE_DHCP_PD
)
258 address
->callback
= dhcp_pd_address_ready_callback
;
260 log_link_debug(link
, "%s(): no DHCP-PD address is ready.", __func__
);
265 link
->dhcp_pd_configured
= true;
267 log_link_debug(link
, "DHCP-PD addresses and routes set.");
269 r
= dhcp_pd_remove(link
, /* only_marked = */ true);
273 link_check_ready(link
);
277 static int dhcp_pd_route_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
, Request
*req
, Link
*link
, Route
*route
) {
284 r
= route_configure_handler_internal(m
, req
, route
);
288 r
= dhcp_pd_check_ready(link
);
290 link_enter_failed(link
);
295 static int dhcp_pd_request_route(Link
*link
, const struct in6_addr
*prefix
, usec_t lifetime_usec
) {
296 _cleanup_(route_unrefp
) Route
*route
= NULL
;
301 assert(link
->manager
);
302 assert(link
->network
);
305 if (link
->network
->dhcp_pd_assign
)
308 r
= route_new(&route
);
312 route
->source
= NETWORK_CONFIG_SOURCE_DHCP_PD
;
313 route
->family
= AF_INET6
;
314 route
->dst
.in6
= *prefix
;
315 route
->dst_prefixlen
= 64;
316 route
->protocol
= RTPROT_DHCP
;
317 route
->priority
= link
->network
->dhcp_pd_route_metric
;
318 route
->lifetime_usec
= lifetime_usec
;
320 r
= route_adjust_nexthops(route
, link
);
324 if (route_get(link
->manager
, route
, &existing
) < 0)
325 link
->dhcp_pd_configured
= false;
327 route_unmark(existing
);
329 r
= link_request_route(link
, route
, &link
->dhcp_pd_messages
, dhcp_pd_route_handler
);
331 return log_link_error_errno(link
, r
, "Failed to request DHCP-PD prefix route: %m");
336 static int dhcp_pd_address_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
, Request
*req
, Link
*link
, Address
*address
) {
342 r
= address_configure_handler_internal(m
, link
, address
);
346 r
= dhcp_pd_check_ready(link
);
348 link_enter_failed(link
);
353 static void log_dhcp_pd_address(Link
*link
, const Address
*address
) {
355 assert(address
->family
== AF_INET6
);
357 int log_level
= address_get_harder(link
, address
, NULL
) >= 0 ? LOG_DEBUG
: LOG_INFO
;
359 if (log_level
< log_get_max_level())
362 log_link_full(link
, log_level
, "DHCP-PD address %s (valid %s, preferred %s)",
363 IN6_ADDR_PREFIX_TO_STRING(&address
->in_addr
.in6
, address
->prefixlen
),
364 FORMAT_LIFETIME(address
->lifetime_valid_usec
),
365 FORMAT_LIFETIME(address
->lifetime_preferred_usec
));
368 static int dhcp_pd_request_address_one(Address
*address
, Link
*link
) {
374 log_dhcp_pd_address(link
, address
);
376 if (address_get(link
, address
, &existing
) < 0)
377 link
->dhcp_pd_configured
= false;
379 address_unmark(existing
);
381 return link_request_address(link
, address
, &link
->dhcp_pd_messages
, dhcp_pd_address_handler
, NULL
);
384 int dhcp_pd_reconfigure_address(Address
*address
, Link
*link
) {
388 assert(address
->source
== NETWORK_CONFIG_SOURCE_DHCP_PD
);
391 r
= regenerate_address(address
, link
);
395 r
= dhcp_pd_request_address_one(address
, link
);
399 if (!link
->dhcp_pd_configured
)
400 link_set_state(link
, LINK_STATE_CONFIGURING
);
402 link_check_ready(link
);
406 static int dhcp_pd_request_address(
408 const struct in6_addr
*prefix
,
409 usec_t lifetime_preferred_usec
,
410 usec_t lifetime_valid_usec
) {
415 assert(link
->network
);
418 if (!link
->network
->dhcp_pd_assign
)
421 _cleanup_hashmap_free_ Hashmap
*tokens_by_address
= NULL
;
422 r
= dhcp_pd_generate_addresses(link
, prefix
, &tokens_by_address
);
424 return log_link_warning_errno(link
, r
, "Failed to generate addresses for acquired DHCP delegated prefix: %m");
428 HASHMAP_FOREACH_KEY(token
, a
, tokens_by_address
) {
429 _cleanup_(address_unrefp
) Address
*address
= NULL
;
431 r
= address_new(&address
);
433 return log_link_error_errno(link
, r
, "Failed to allocate address for DHCP delegated prefix: %m");
435 address
->source
= NETWORK_CONFIG_SOURCE_DHCP_PD
;
436 address
->family
= AF_INET6
;
437 address
->in_addr
.in6
= *a
;
438 address
->prefixlen
= 64;
439 address
->lifetime_preferred_usec
= lifetime_preferred_usec
;
440 address
->lifetime_valid_usec
= lifetime_valid_usec
;
441 SET_FLAG(address
->flags
, IFA_F_MANAGETEMPADDR
, link
->network
->dhcp_pd_manage_temporary_address
);
442 address
->route_metric
= link
->network
->dhcp_pd_route_metric
;
443 address
->token
= ipv6_token_ref(token
);
445 r
= free_and_strdup_warn(&address
->netlabel
, link
->network
->dhcp_pd_netlabel
);
449 r
= dhcp_pd_request_address_one(address
, link
);
451 return log_link_error_errno(link
, r
, "Failed to request DHCP delegated prefix address: %m");
457 static int dhcp_pd_calculate_subnet_prefix(
458 const struct in6_addr
*pd_prefix
,
459 uint8_t pd_prefix_len
,
461 struct in6_addr
*ret
) {
463 struct in6_addr prefix
;
466 assert(pd_prefix_len
<= 64);
469 if (subnet_id
>= UINT64_C(1) << (64 - pd_prefix_len
))
474 if (pd_prefix_len
< 32)
475 prefix
.s6_addr32
[0] |= htobe32(subnet_id
>> 32);
477 prefix
.s6_addr32
[1] |= htobe32(subnet_id
& 0xffffffff);
483 static int dhcp_pd_get_preferred_subnet_prefix(
485 const struct in6_addr
*pd_prefix
,
486 uint8_t pd_prefix_len
,
487 struct in6_addr
*ret
) {
489 struct in6_addr prefix
;
494 assert(link
->manager
);
495 assert(link
->network
);
498 if (link
->network
->dhcp_pd_subnet_id
>= 0) {
499 /* If the link has a preference for a particular subnet id try to allocate that */
501 r
= dhcp_pd_calculate_subnet_prefix(pd_prefix
, pd_prefix_len
, link
->network
->dhcp_pd_subnet_id
, &prefix
);
503 return log_link_warning_errno(link
, r
,
504 "subnet id %" PRIi64
" is out of range. Only have %" PRIu64
" subnets.",
505 link
->network
->dhcp_pd_subnet_id
, UINT64_C(1) << (64 - pd_prefix_len
));
511 if (dhcp_pd_get_assigned_subnet_prefix(link
, pd_prefix
, pd_prefix_len
, ret
) >= 0)
514 for (uint64_t n
= 0; ; n
++) {
515 /* If we do not have an allocation preference just iterate
516 * through the address space and return the first free prefix. */
518 r
= dhcp_pd_calculate_subnet_prefix(pd_prefix
, pd_prefix_len
, n
, &prefix
);
520 return log_link_warning_errno(link
, r
,
521 "Couldn't find a suitable prefix. Ran out of address space.");
523 /* Do not use explicitly requested subnet IDs. Note that the corresponding link may not
524 * appear yet. So, we need to check the ID is not used in any .network files. */
525 if (set_contains(link
->manager
->dhcp_pd_subnet_ids
, &n
))
528 /* Check that the prefix is not assigned to another link. */
529 if (link_get_by_dhcp_pd_subnet_prefix(link
->manager
, &prefix
, &assigned_link
) < 0 ||
530 assigned_link
== link
)
534 r
= link_add_dhcp_pd_subnet_prefix(link
, &prefix
);
536 return log_link_warning_errno(link
, r
, "Failed to save acquired free subnet prefix: %m");
542 static int dhcp_pd_assign_subnet_prefix(
544 const struct in6_addr
*pd_prefix
,
545 uint8_t pd_prefix_len
,
546 usec_t lifetime_preferred_usec
,
547 usec_t lifetime_valid_usec
,
550 struct in6_addr prefix
;
554 assert(link
->network
);
557 r
= dhcp_pd_get_preferred_subnet_prefix(link
, pd_prefix
, pd_prefix_len
, &prefix
);
559 return r
== -ERANGE
? 0 : r
;
561 const char *pretty
= IN6_ADDR_PREFIX_TO_STRING(&prefix
, 64);
563 if (link_radv_enabled(link
) && link
->network
->dhcp_pd_announce
) {
565 log_link_debug(link
, "Ignoring Announce= setting on upstream interface.");
567 r
= radv_add_prefix(link
, &prefix
, 64, lifetime_preferred_usec
, lifetime_valid_usec
);
569 return log_link_warning_errno(link
, r
,
570 "Failed to assign/update prefix %s to IPv6 Router Advertisement: %m",
575 r
= dhcp_pd_request_route(link
, &prefix
, lifetime_valid_usec
);
577 return log_link_warning_errno(link
, r
,
578 "Failed to assign/update route for prefix %s: %m", pretty
);
580 r
= dhcp_pd_request_address(link
, &prefix
, lifetime_preferred_usec
, lifetime_valid_usec
);
582 return log_link_warning_errno(link
, r
,
583 "Failed to assign/update address for prefix %s: %m", pretty
);
585 log_link_debug(link
, "Assigned prefix %s", pretty
);
589 static int dhcp_pd_prepare(Link
*link
) {
590 if (!IN_SET(link
->state
, LINK_STATE_CONFIGURING
, LINK_STATE_CONFIGURED
))
593 if (!link_dhcp_pd_is_enabled(link
))
596 if (link_radv_enabled(link
) && link
->network
->dhcp_pd_announce
&& !link
->radv
)
599 link_mark_addresses(link
, NETWORK_CONFIG_SOURCE_DHCP_PD
);
600 manager_mark_routes(link
->manager
, link
, NETWORK_CONFIG_SOURCE_DHCP_PD
);
605 static int dhcp_pd_finalize(Link
*link
) {
608 if (!IN_SET(link
->state
, LINK_STATE_CONFIGURING
, LINK_STATE_CONFIGURED
))
611 if (link
->dhcp_pd_messages
== 0) {
612 link
->dhcp_pd_configured
= false;
614 r
= dhcp_pd_remove(link
, /* only_marked = */ true);
619 if (!link
->dhcp_pd_configured
)
620 link_set_state(link
, LINK_STATE_CONFIGURING
);
622 link_check_ready(link
);
626 static void dhcp_pd_mark_unreachable_route(Manager
*manager
, NetworkConfigSource source
) {
630 SET_FOREACH(route
, manager
->routes
) {
631 if (route
->source
!= source
)
633 if (route
->family
!= AF_INET6
)
635 if (route
->nexthop
.ifindex
!= 0) /* IPv6 unreachable has 0 ifindex. */
637 if (!route_type_is_reject(route
->type
))
644 static int dhcp_pd_remove_unreachable_route(Manager
*manager
, NetworkConfigSource source
, bool only_marked
) {
650 SET_FOREACH(route
, manager
->routes
) {
651 if (route
->source
!= source
)
653 if (route
->family
!= AF_INET6
)
655 if (route
->nexthop
.ifindex
!= 0) /* IPv6 unreachable has 0 ifindex. */
657 if (!route_type_is_reject(route
->type
))
659 if (only_marked
&& !route_is_marked(route
))
662 RET_GATHER(ret
, route_remove_and_cancel(route
, manager
));
668 static void dhcp_pd_prefix_lost(Link
*uplink
, NetworkConfigSource source
) {
673 assert(uplink
->manager
);
675 HASHMAP_FOREACH(link
, uplink
->manager
->links_by_index
) {
676 if (!dhcp_pd_is_uplink(link
, uplink
, /* accept_auto = */ true))
679 r
= dhcp_pd_remove(link
, /* only_marked = */ false);
681 link_enter_failed(link
);
684 (void) dhcp_pd_remove_unreachable_route(uplink
->manager
, source
, /* only_marked = */ false);
686 set_clear(uplink
->dhcp_pd_prefixes
);
689 void dhcp4_pd_prefix_lost(Link
*uplink
) {
693 assert(uplink
->manager
);
695 dhcp_pd_prefix_lost(uplink
, NETWORK_CONFIG_SOURCE_DHCP4
);
697 if (uplink
->dhcp4_6rd_tunnel_name
&&
698 link_get_by_name(uplink
->manager
, uplink
->dhcp4_6rd_tunnel_name
, &tunnel
) >= 0)
699 (void) link_remove(tunnel
);
702 void dhcp6_pd_prefix_lost(Link
*uplink
) {
703 dhcp_pd_prefix_lost(uplink
, NETWORK_CONFIG_SOURCE_DHCP6
);
706 static int dhcp4_unreachable_route_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
, Request
*req
, Link
*link
, Route
*route
) {
713 r
= route_configure_handler_internal(m
, req
, route
);
717 r
= dhcp4_check_ready(link
);
719 link_enter_failed(link
);
724 static int dhcp6_unreachable_route_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
, Request
*req
, Link
*link
, Route
*route
) {
731 r
= route_configure_handler_internal(m
, req
, route
);
735 r
= dhcp6_check_ready(link
);
737 link_enter_failed(link
);
742 static int dhcp_request_unreachable_route(
744 const struct in6_addr
*addr
,
746 usec_t lifetime_usec
,
747 NetworkConfigSource source
,
748 const union in_addr_union
*server_address
,
749 uint8_t type
, /* RTN_* */
751 route_netlink_handler_t callback
,
754 _cleanup_(route_unrefp
) Route
*route
= NULL
;
759 assert(link
->manager
);
761 assert(IN_SET(source
, NETWORK_CONFIG_SOURCE_DHCP4
, NETWORK_CONFIG_SOURCE_DHCP6
));
762 assert(server_address
);
763 assert(type
== RTN_UNSPEC
|| route_type_is_reject(type
));
768 if (type
== RTN_UNSPEC
)
769 return 0; /* Disabled. */
771 if (prefixlen
>= 64) {
772 log_link_debug(link
, "Not adding a blocking route for DHCP delegated prefix %s since the prefix has length >= 64.",
773 IN6_ADDR_PREFIX_TO_STRING(addr
, prefixlen
));
777 r
= route_new(&route
);
781 route
->source
= source
;
782 route
->provider
= *server_address
;
783 route
->family
= AF_INET6
;
784 route
->dst
.in6
= *addr
;
785 route
->dst_prefixlen
= prefixlen
;
787 route
->protocol
= RTPROT_DHCP
;
788 route
->priority
= IP6_RT_PRIO_USER
;
789 route
->lifetime_usec
= lifetime_usec
;
791 r
= route_adjust_nexthops(route
, link
);
795 if (route_get(link
->manager
, route
, &existing
) < 0)
798 route_unmark(existing
);
800 r
= link_request_route(link
, route
, counter
, callback
);
802 return log_link_error_errno(link
, r
, "Failed to request unreachable route for DHCP delegated prefix %s: %m",
803 IN6_ADDR_PREFIX_TO_STRING(addr
, prefixlen
));
808 static int dhcp4_request_unreachable_route(
810 const struct in6_addr
*addr
,
812 usec_t lifetime_usec
,
813 const union in_addr_union
*server_address
) {
816 assert(link
->network
);
818 return dhcp_request_unreachable_route(link
, addr
, prefixlen
, lifetime_usec
,
819 NETWORK_CONFIG_SOURCE_DHCP4
, server_address
,
820 link
->network
->dhcp_6rd_prefix_route_type
,
821 &link
->dhcp4_messages
, dhcp4_unreachable_route_handler
,
822 &link
->dhcp4_configured
);
825 static int dhcp6_request_unreachable_route(
827 const struct in6_addr
*addr
,
829 usec_t lifetime_usec
,
830 const union in_addr_union
*server_address
) {
833 assert(link
->network
);
835 return dhcp_request_unreachable_route(link
, addr
, prefixlen
, lifetime_usec
,
836 NETWORK_CONFIG_SOURCE_DHCP6
, server_address
,
837 link
->network
->dhcp6_pd_prefix_route_type
,
838 &link
->dhcp6_messages
, dhcp6_unreachable_route_handler
,
839 &link
->dhcp6_configured
);
842 static int dhcp_pd_prefix_add(Link
*link
, const struct in6_addr
*prefix
, uint8_t prefixlen
) {
843 struct in_addr_prefix
*p
;
849 p
= new(struct in_addr_prefix
, 1);
853 *p
= (struct in_addr_prefix
) {
855 .prefixlen
= prefixlen
,
856 .address
.in6
= *prefix
,
859 int log_level
= set_contains(link
->dhcp_pd_prefixes
, p
) ? LOG_DEBUG
:
860 prefixlen
> 64 || prefixlen
< 48 ? LOG_WARNING
: LOG_INFO
;
863 "DHCP: received delegated prefix %s%s",
864 IN6_ADDR_PREFIX_TO_STRING(prefix
, prefixlen
),
865 prefixlen
> 64 ? " with prefix length > 64, ignoring." :
866 prefixlen
< 48 ? " with prefix length < 48, looks unusual.": "");
868 /* Store PD prefix even if prefixlen > 64, not to make logged at warning level so frequently. */
869 r
= set_ensure_consume(&link
->dhcp_pd_prefixes
, &in_addr_prefix_hash_ops_free
, p
);
871 return log_link_error_errno(link
, r
, "Failed to store DHCP delegated prefix %s: %m",
872 IN6_ADDR_PREFIX_TO_STRING(prefix
, prefixlen
));
876 static int dhcp4_pd_request_default_gateway_on_6rd_tunnel(Link
*link
, const struct in_addr
*br_address
, usec_t lifetime_usec
) {
877 _cleanup_(route_unrefp
) Route
*route
= NULL
;
882 assert(link
->manager
);
885 r
= route_new(&route
);
887 return log_link_debug_errno(link
, r
, "Failed to allocate default gateway for DHCP delegated prefix: %m");
889 route
->source
= NETWORK_CONFIG_SOURCE_DHCP_PD
;
890 route
->family
= AF_INET6
;
891 route
->nexthop
.family
= AF_INET6
;
892 route
->nexthop
.gw
.in6
.s6_addr32
[3] = br_address
->s_addr
;
893 route
->scope
= RT_SCOPE_UNIVERSE
;
894 route
->protocol
= RTPROT_DHCP
;
895 route
->priority
= IP6_RT_PRIO_USER
;
896 route
->lifetime_usec
= lifetime_usec
;
898 r
= route_adjust_nexthops(route
, link
);
902 if (route_get(link
->manager
, route
, &existing
) < 0) /* This is a new route. */
903 link
->dhcp_pd_configured
= false;
905 route_unmark(existing
);
907 r
= link_request_route(link
, route
, &link
->dhcp_pd_messages
, dhcp_pd_route_handler
);
909 return log_link_debug_errno(link
, r
, "Failed to request default gateway for DHCP delegated prefix: %m");
914 static void dhcp4_calculate_pd_prefix(
915 const struct in_addr
*ipv4address
,
917 const struct in6_addr
*sixrd_prefix
,
918 uint8_t sixrd_prefixlen
,
919 struct in6_addr
*ret_pd_prefix
,
920 uint8_t *ret_pd_prefixlen
) {
922 struct in6_addr pd_prefix
;
925 assert(ipv4masklen
<= 32);
926 assert(sixrd_prefix
);
927 assert(32 - ipv4masklen
+ sixrd_prefixlen
<= 128);
928 assert(ret_pd_prefix
);
930 pd_prefix
= *sixrd_prefix
;
931 for (unsigned i
= 0; i
< (unsigned) (32 - ipv4masklen
); i
++)
932 if (ipv4address
->s_addr
& htobe32(UINT32_C(1) << (32 - ipv4masklen
- i
- 1)))
933 pd_prefix
.s6_addr
[(i
+ sixrd_prefixlen
) / 8] |= 1 << (7 - (i
+ sixrd_prefixlen
) % 8);
935 *ret_pd_prefix
= pd_prefix
;
936 if (ret_pd_prefixlen
)
937 *ret_pd_prefixlen
= 32 - ipv4masklen
+ sixrd_prefixlen
;
940 static int dhcp4_pd_assign_subnet_prefix(Link
*link
, Link
*uplink
) {
941 uint8_t ipv4masklen
, sixrd_prefixlen
, pd_prefixlen
;
942 struct in6_addr sixrd_prefix
, pd_prefix
;
943 const struct in_addr
*br_addresses
;
944 struct in_addr ipv4address
;
945 usec_t lifetime_usec
;
950 assert(uplink
->manager
);
951 assert(uplink
->dhcp_lease
);
953 r
= sd_dhcp_lease_get_address(uplink
->dhcp_lease
, &ipv4address
);
955 return log_link_warning_errno(uplink
, r
, "Failed to get DHCPv4 address: %m");
957 r
= sd_dhcp_lease_get_lifetime_timestamp(uplink
->dhcp_lease
, CLOCK_BOOTTIME
, &lifetime_usec
);
959 return log_link_warning_errno(uplink
, r
, "Failed to get lifetime of DHCPv4 lease: %m");
961 r
= sd_dhcp_lease_get_6rd(uplink
->dhcp_lease
, &ipv4masklen
, &sixrd_prefixlen
, &sixrd_prefix
, &br_addresses
, NULL
);
963 return log_link_warning_errno(uplink
, r
, "Failed to get DHCPv4 6rd option: %m");
965 dhcp4_calculate_pd_prefix(&ipv4address
, ipv4masklen
, &sixrd_prefix
, sixrd_prefixlen
, &pd_prefix
, &pd_prefixlen
);
967 if (pd_prefixlen
> 64)
970 r
= dhcp_pd_prepare(link
);
974 if (streq_ptr(uplink
->dhcp4_6rd_tunnel_name
, link
->ifname
)) {
975 r
= dhcp4_pd_request_default_gateway_on_6rd_tunnel(link
, &br_addresses
[0], lifetime_usec
);
980 r
= dhcp_pd_assign_subnet_prefix(link
, &pd_prefix
, pd_prefixlen
, lifetime_usec
, lifetime_usec
, /* is_uplink = */ false);
984 return dhcp_pd_finalize(link
);
987 static int dhcp4_pd_6rd_tunnel_create_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
, Link
*link
) {
992 assert(link
->manager
);
993 assert(link
->dhcp4_6rd_tunnel_name
);
995 if (IN_SET(link
->state
, LINK_STATE_FAILED
, LINK_STATE_LINGER
))
998 r
= sd_netlink_message_get_errno(m
);
1000 log_link_message_warning_errno(link
, m
, r
, "Failed to create tunnel device for DHCPv4 6rd");
1001 link_enter_failed(link
);
1008 int dhcp4_pd_prefix_acquired(Link
*uplink
) {
1009 uint8_t ipv4masklen
, sixrd_prefixlen
, pd_prefixlen
;
1010 struct in6_addr sixrd_prefix
, pd_prefix
;
1011 struct in_addr ipv4address
;
1012 union in_addr_union server_address
;
1013 const struct in_addr
*br_addresses
;
1014 usec_t lifetime_usec
;
1019 assert(uplink
->manager
);
1020 assert(uplink
->dhcp_lease
);
1022 r
= sd_dhcp_lease_get_address(uplink
->dhcp_lease
, &ipv4address
);
1024 return log_link_warning_errno(uplink
, r
, "Failed to get DHCPv4 address: %m");
1026 r
= sd_dhcp_lease_get_lifetime_timestamp(uplink
->dhcp_lease
, CLOCK_BOOTTIME
, &lifetime_usec
);
1028 return log_link_warning_errno(uplink
, r
, "Failed to get lifetime of DHCPv4 lease: %m");
1030 r
= sd_dhcp_lease_get_server_identifier(uplink
->dhcp_lease
, &server_address
.in
);
1032 return log_link_warning_errno(uplink
, r
, "Failed to get server address of DHCPv4 lease: %m");
1034 r
= sd_dhcp_lease_get_6rd(uplink
->dhcp_lease
, &ipv4masklen
, &sixrd_prefixlen
, &sixrd_prefix
, &br_addresses
, NULL
);
1036 return log_link_warning_errno(uplink
, r
, "Failed to get DHCPv4 6rd option: %m");
1039 log_link_debug(uplink
, "DHCPv4: 6rd option is acquired: IPv4_masklen=%u, 6rd_prefix=%s, br_address="IPV4_ADDRESS_FMT_STR
,
1041 IN6_ADDR_PREFIX_TO_STRING(&sixrd_prefix
, sixrd_prefixlen
),
1042 IPV4_ADDRESS_FMT_VAL(*br_addresses
));
1044 /* Calculate PD prefix */
1045 dhcp4_calculate_pd_prefix(&ipv4address
, ipv4masklen
, &sixrd_prefix
, sixrd_prefixlen
, &pd_prefix
, &pd_prefixlen
);
1047 /* Register and log PD prefix */
1048 r
= dhcp_pd_prefix_add(uplink
, &pd_prefix
, pd_prefixlen
);
1052 /* Request unreachable route */
1053 dhcp_pd_mark_unreachable_route(uplink
->manager
, NETWORK_CONFIG_SOURCE_DHCP4
);
1054 r
= dhcp4_request_unreachable_route(uplink
, &pd_prefix
, pd_prefixlen
, lifetime_usec
, &server_address
);
1057 (void) dhcp_pd_remove_unreachable_route(uplink
->manager
, NETWORK_CONFIG_SOURCE_DHCP4
, /* only_marked = */ true);
1059 /* Create or update 6rd SIT tunnel device. */
1060 r
= dhcp4_pd_create_6rd_tunnel(uplink
, dhcp4_pd_6rd_tunnel_create_handler
);
1062 return log_link_warning_errno(uplink
, r
, "Failed to create or update 6rd SIT tunnel: %m");
1064 /* Then, assign subnet prefixes to downstream interfaces. */
1065 HASHMAP_FOREACH(link
, uplink
->manager
->links_by_index
) {
1066 if (!dhcp_pd_is_uplink(link
, uplink
, /* accept_auto = */ true))
1069 r
= dhcp4_pd_assign_subnet_prefix(link
, uplink
);
1071 /* When failed on the upstream interface (i.e., the case link == uplink),
1072 * immediately abort the assignment of the prefixes. As, the all assigned
1073 * prefixes will be dropped soon in link_enter_failed(), and it is meaningless
1074 * to continue the assignment. */
1078 link_enter_failed(link
);
1085 static int dhcp6_pd_assign_subnet_prefixes(Link
*link
, Link
*uplink
) {
1090 assert(uplink
->dhcp6_lease
);
1092 r
= dhcp_pd_prepare(link
);
1096 FOREACH_DHCP6_PD_PREFIX(uplink
->dhcp6_lease
) {
1097 usec_t lifetime_preferred_usec
, 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 if (pd_prefix_len
> 64)
1108 /* Mask prefix for safety. */
1109 r
= in6_addr_mask(&pd_prefix
, pd_prefix_len
);
1113 r
= sd_dhcp6_lease_get_pd_lifetime_timestamp(uplink
->dhcp6_lease
, CLOCK_BOOTTIME
,
1114 &lifetime_preferred_usec
, &lifetime_valid_usec
);
1118 r
= dhcp_pd_assign_subnet_prefix(link
, &pd_prefix
, pd_prefix_len
,
1119 lifetime_preferred_usec
, lifetime_valid_usec
,
1120 /* is_uplink = */ link
== uplink
);
1125 return dhcp_pd_finalize(link
);
1128 int dhcp6_pd_prefix_acquired(Link
*uplink
) {
1129 union in_addr_union server_address
;
1134 assert(uplink
->dhcp6_lease
);
1135 assert(uplink
->manager
);
1137 r
= sd_dhcp6_lease_get_server_address(uplink
->dhcp6_lease
, &server_address
.in6
);
1139 return log_link_warning_errno(uplink
, r
, "Failed to get server address of DHCPv6 lease: %m");
1141 dhcp_pd_mark_unreachable_route(uplink
->manager
, NETWORK_CONFIG_SOURCE_DHCP6
);
1143 /* First, logs acquired prefixes and request unreachable routes. */
1144 FOREACH_DHCP6_PD_PREFIX(uplink
->dhcp6_lease
) {
1145 usec_t lifetime_valid_usec
;
1146 struct in6_addr pd_prefix
;
1147 uint8_t pd_prefix_len
;
1149 r
= sd_dhcp6_lease_get_pd_prefix(uplink
->dhcp6_lease
, &pd_prefix
, &pd_prefix_len
);
1153 /* Mask prefix for safety. */
1154 r
= in6_addr_mask(&pd_prefix
, pd_prefix_len
);
1156 return log_link_error_errno(uplink
, r
, "Failed to mask DHCPv6 delegated prefix: %m");
1158 r
= dhcp_pd_prefix_add(uplink
, &pd_prefix
, pd_prefix_len
);
1162 r
= sd_dhcp6_lease_get_pd_lifetime_timestamp(uplink
->dhcp6_lease
, CLOCK_BOOTTIME
,
1163 NULL
, &lifetime_valid_usec
);
1167 r
= dhcp6_request_unreachable_route(uplink
, &pd_prefix
, pd_prefix_len
,
1168 lifetime_valid_usec
, &server_address
);
1173 (void) dhcp_pd_remove_unreachable_route(uplink
->manager
, NETWORK_CONFIG_SOURCE_DHCP6
, /* only_marked = */ true);
1175 /* Then, assign subnet prefixes. */
1176 HASHMAP_FOREACH(link
, uplink
->manager
->links_by_index
) {
1177 if (!dhcp_pd_is_uplink(link
, uplink
, /* accept_auto = */ true))
1180 r
= dhcp6_pd_assign_subnet_prefixes(link
, uplink
);
1182 /* When failed on the upstream interface (i.e., the case link == uplink),
1183 * immediately abort the assignment of the prefixes. As, the all assigned
1184 * prefixes will be dropped soon in link_enter_failed(), and it is meaningless
1185 * to continue the assignment. */
1189 link_enter_failed(link
);
1196 static bool dhcp4_pd_uplink_is_ready(Link
*link
) {
1202 if (!link
->network
->dhcp_use_6rd
)
1205 if (!IN_SET(link
->state
, LINK_STATE_CONFIGURING
, LINK_STATE_CONFIGURED
))
1208 if (!link
->dhcp_client
)
1211 if (sd_dhcp_client_is_running(link
->dhcp_client
) <= 0)
1214 return sd_dhcp_lease_has_6rd(link
->dhcp_lease
);
1217 static bool dhcp6_pd_uplink_is_ready(Link
*link
) {
1223 if (!link
->network
->dhcp6_use_pd_prefix
)
1226 if (!IN_SET(link
->state
, LINK_STATE_CONFIGURING
, LINK_STATE_CONFIGURED
))
1229 if (!link
->dhcp6_client
)
1232 if (sd_dhcp6_client_is_running(link
->dhcp6_client
) <= 0)
1235 return sd_dhcp6_lease_has_pd_prefix(link
->dhcp6_lease
);
1238 int dhcp_pd_find_uplink(Link
*link
, Link
**ret
) {
1239 Link
*uplink
= NULL
;
1243 assert(link
->manager
);
1244 assert(link_dhcp_pd_is_enabled(link
));
1247 if (link
->network
->dhcp_pd_uplink_name
)
1248 r
= link_get_by_name(link
->manager
, link
->network
->dhcp_pd_uplink_name
, &uplink
);
1249 else if (link
->network
->dhcp_pd_uplink_index
> 0)
1250 r
= link_get_by_index(link
->manager
, link
->network
->dhcp_pd_uplink_index
, &uplink
);
1251 else if (link
->network
->dhcp_pd_uplink_index
== UPLINK_INDEX_SELF
)
1257 if (dhcp4_pd_uplink_is_ready(uplink
)) {
1262 if (dhcp6_pd_uplink_is_ready(uplink
)) {
1270 HASHMAP_FOREACH(uplink
, link
->manager
->links_by_index
) {
1271 /* Assume that there exists at most one link which acquired delegated prefixes. */
1272 if (dhcp4_pd_uplink_is_ready(uplink
)) {
1277 if (dhcp6_pd_uplink_is_ready(uplink
)) {
1286 int dhcp_request_prefix_delegation(Link
*link
) {
1292 if (!link_dhcp_pd_is_enabled(link
))
1295 r
= dhcp_pd_find_uplink(link
, &uplink
);
1299 log_link_debug(link
, "Requesting subnets of delegated prefixes acquired by DHCPv%c client on %s",
1300 r
== AF_INET
? '4' : '6', uplink
->ifname
);
1302 return r
== AF_INET
?
1303 dhcp4_pd_assign_subnet_prefix(link
, uplink
) :
1304 dhcp6_pd_assign_subnet_prefixes(link
, uplink
);
1307 int link_drop_dhcp_pd_config(Link
*link
, Network
*network
) {
1309 assert(link
->network
);
1311 if (link
->network
== network
)
1312 return 0; /* .network file is unchanged. It is not necessary to reconfigure the client. */
1314 if (!link_dhcp_pd_is_enabled(link
)) /* Disabled now, drop all configs. */
1315 return dhcp_pd_remove(link
, /* only_marked = */ false);
1317 /* If previously explicitly disabled, then there is nothing we need to drop.
1318 * If this is called on start up, we do not know the previous settings, assume nothing changed. */
1319 if (!network
|| !network
->dhcp_pd
)
1322 /* If at least one setting is changed, then drop all configurations. */
1323 if (link
->network
->dhcp_pd_assign
!= network
->dhcp_pd_assign
||
1324 (link
->network
->dhcp_pd_assign
&&
1325 (link
->network
->dhcp_pd_manage_temporary_address
!= network
->dhcp_pd_manage_temporary_address
||
1326 !set_equal(link
->network
->dhcp_pd_tokens
, network
->dhcp_pd_tokens
))) ||
1327 link
->network
->dhcp_pd_subnet_id
!= network
->dhcp_pd_subnet_id
||
1328 link
->network
->dhcp_pd_route_metric
!= network
->dhcp_pd_route_metric
||
1329 link
->network
->dhcp_pd_uplink_index
!= network
->dhcp_pd_uplink_index
||
1330 !streq_ptr(link
->network
->dhcp_pd_uplink_name
, network
->dhcp_pd_uplink_name
))
1331 return dhcp_pd_remove(link
, /* only_marked = */ false);
1336 int config_parse_dhcp_pd_subnet_id(
1338 const char *filename
,
1340 const char *section
,
1341 unsigned section_line
,
1348 int64_t *p
= ASSERT_PTR(data
);
1356 if (isempty(rvalue
) || streq(rvalue
, "auto")) {
1361 r
= safe_atoux64(rvalue
, &t
);
1363 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1364 "Failed to parse %s=, ignoring assignment: %s",
1368 if (t
> INT64_MAX
) {
1369 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
1370 "Invalid subnet id '%s', ignoring assignment.",
1380 int config_parse_dhcp_pd_prefix_route_type(
1382 const char *filename
,
1384 const char *section
,
1385 unsigned section_line
,
1392 uint8_t *p
= ASSERT_PTR(data
);
1399 if (isempty(rvalue
)) {
1400 *p
= RTN_UNREACHABLE
; /* Defaults to unreachable. */
1404 if (streq(rvalue
, "none")) {
1405 *p
= RTN_UNSPEC
; /* Indicate that the route is disabled. */
1409 r
= route_type_from_string(rvalue
);
1411 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1412 "Failed to parse %s=, ignoring assignment: %s",
1417 if (!route_type_is_reject(r
)) {
1418 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
1419 "Invalid route type is specified to %s=, ignoring assignment: %s",