Closes #19152.
--- /dev/null
+# SPDX-License-Identifier: LGPL-2.1-or-later
+#
+# This file is part of systemd.
+#
+# systemd is free software; you can redistribute it and/or modify it
+# under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; either version 2.1 of the License, or
+# (at your option) any later version.
+
+# This network file matches 6rd-* SIT devices which is automatically created by
+# systemd-networkd when DHCPv4 6RD option is received.
+
+[Match]
+Name=6rd-*
+Type=sit
+
+[Network]
+DHCPPrefixDelegation=yes
# SPDX-License-Identifier: LGPL-2.1-or-later
if conf.get('ENABLE_NETWORKD') == 1
- install_data('80-container-host0.network',
+ install_data('80-6rd-tunnel.network',
+ '80-container-host0.network',
'80-container-ve.network',
'80-container-vz.network',
'80-vm-vt.network',
#include <linux/ip6_tunnel.h>
#include "conf-parser.h"
+#include "hexdecoct.h"
#include "missing_network.h"
#include "netlink-util.h"
+#include "networkd-manager.h"
#include "parse-util.h"
+#include "siphash24.h"
#include "string-table.h"
#include "string-util.h"
#include "tunnel.h"
DEFINE_STRING_TABLE_LOOKUP(ip6tnl_mode, Ip6TnlMode);
DEFINE_CONFIG_PARSE_ENUM(config_parse_ip6tnl_mode, ip6tnl_mode, Ip6TnlMode, "Failed to parse ip6 tunnel Mode");
+#define HASH_KEY SD_ID128_MAKE(74,c4,de,12,f3,d9,41,34,bb,3d,c1,a4,42,93,50,87)
+
+int dhcp4_pd_create_6rd_tunnel_name(Link *link, char **ret) {
+ _cleanup_free_ char *ifname_alloc = NULL;
+ uint8_t ipv4masklen, sixrd_prefixlen, *buf, *p;
+ struct in_addr ipv4address;
+ struct in6_addr sixrd_prefix;
+ char ifname[IFNAMSIZ];
+ uint64_t result;
+ size_t sz;
+ int r;
+
+ assert(link);
+ assert(link->dhcp_lease);
+
+ r = sd_dhcp_lease_get_address(link->dhcp_lease, &ipv4address);
+ if (r < 0)
+ return log_link_debug_errno(link, r, "Failed to get DHCPv4 address: %m");
+
+ r = sd_dhcp_lease_get_6rd(link->dhcp_lease, &ipv4masklen, &sixrd_prefixlen, &sixrd_prefix, NULL, NULL);
+ if (r < 0)
+ return log_link_debug_errno(link, r, "Failed to get 6rd option: %m");
+
+ sz = sizeof(uint8_t) * 2 + sizeof(struct in6_addr) + sizeof(struct in_addr);
+ buf = newa(uint8_t, sz);
+ p = buf;
+ p = mempcpy(p, &ipv4masklen, sizeof(uint8_t));
+ p = mempcpy(p, &ipv4address, sizeof(struct in_addr));
+ p = mempcpy(p, &sixrd_prefixlen, sizeof(uint8_t));
+ p = mempcpy(p, &sixrd_prefix, sizeof(struct in6_addr));
+
+ result = siphash24(buf, sz, HASH_KEY.bytes);
+ memcpy(ifname, "6rd-", STRLEN("6rd-"));
+ ifname[STRLEN("6rd-") ] = urlsafe_base64char(result >> 54);
+ ifname[STRLEN("6rd-") + 1] = urlsafe_base64char(result >> 48);
+ ifname[STRLEN("6rd-") + 2] = urlsafe_base64char(result >> 42);
+ ifname[STRLEN("6rd-") + 3] = urlsafe_base64char(result >> 36);
+ ifname[STRLEN("6rd-") + 4] = urlsafe_base64char(result >> 30);
+ ifname[STRLEN("6rd-") + 5] = urlsafe_base64char(result >> 24);
+ ifname[STRLEN("6rd-") + 6] = urlsafe_base64char(result >> 18);
+ ifname[STRLEN("6rd-") + 7] = urlsafe_base64char(result >> 12);
+ ifname[STRLEN("6rd-") + 8] = urlsafe_base64char(result >> 6);
+ ifname[STRLEN("6rd-") + 9] = urlsafe_base64char(result);
+ ifname[STRLEN("6rd-") + 10] = '\0';
+ assert_cc(STRLEN("6rd-") + 10 <= IFNAMSIZ);
+
+ ifname_alloc = strdup(ifname);
+ if (!ifname_alloc)
+ return log_oom_debug();
+
+ *ret = TAKE_PTR(ifname_alloc);
+ return 0;
+}
+
+int dhcp4_pd_create_6rd_tunnel(Link *link, link_netlink_message_handler_t callback) {
+ _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
+ uint8_t ipv4masklen, sixrd_prefixlen;
+ struct in_addr ipv4address, relay_prefix;
+ struct in6_addr sixrd_prefix;
+ int r;
+
+ assert(link);
+ assert(link->ifindex > 0);
+ assert(link->manager);
+ assert(link->dhcp_lease);
+ assert(link->dhcp4_6rd_tunnel_name);
+ assert(callback);
+
+ r = sd_dhcp_lease_get_address(link->dhcp_lease, &ipv4address);
+ if (r < 0)
+ return log_link_debug_errno(link, r, "Failed to get DHCPv4 address: %m");
+
+ r = sd_dhcp_lease_get_6rd(link->dhcp_lease, &ipv4masklen, &sixrd_prefixlen, &sixrd_prefix, NULL, NULL);
+ if (r < 0)
+ return log_link_debug_errno(link, r, "Failed to get 6rd option: %m");
+
+ r = sd_rtnl_message_new_link(link->manager->rtnl, &m, RTM_NEWLINK, 0);
+ if (r < 0)
+ return log_link_debug_errno(link, r, "Could not allocate RTM_NEWLINK message: %m");
+
+ r = sd_netlink_message_append_string(m, IFLA_IFNAME, link->dhcp4_6rd_tunnel_name);
+ if (r < 0)
+ return log_link_debug_errno(link, r, "Could not append IFLA_IFNAME, attribute: %m");
+
+ r = sd_netlink_message_open_container(m, IFLA_LINKINFO);
+ if (r < 0)
+ return log_link_debug_errno(link, r, "Could not append IFLA_LINKINFO attribute: %m");
+
+ r = sd_netlink_message_open_container_union(m, IFLA_INFO_DATA, "sit");
+ if (r < 0)
+ return log_link_debug_errno(link, r, "Could not append IFLA_INFO_DATA attribute: %m");
+
+ r = sd_netlink_message_append_u32(m, IFLA_IPTUN_LINK, link->ifindex);
+ if (r < 0)
+ return log_link_debug_errno(link, r, "Could not append IFLA_IPTUN_LINK attribute: %m");
+
+ r = sd_netlink_message_append_in_addr(m, IFLA_IPTUN_LOCAL, &ipv4address);
+ if (r < 0)
+ return log_link_debug_errno(link, r, "Could not append IFLA_IPTUN_LOCAL attribute: %m");
+
+ r = sd_netlink_message_append_u8(m, IFLA_IPTUN_TTL, 64);
+ if (r < 0)
+ return log_link_debug_errno(link, r, "Could not append IFLA_IPTUN_TTL attribute: %m");
+
+ r = sd_netlink_message_append_in6_addr(m, IFLA_IPTUN_6RD_PREFIX, &sixrd_prefix);
+ if (r < 0)
+ return log_link_debug_errno(link, r, "Could not append IFLA_IPTUN_6RD_PREFIX attribute: %m");
+
+ r = sd_netlink_message_append_u16(m, IFLA_IPTUN_6RD_PREFIXLEN, sixrd_prefixlen);
+ if (r < 0)
+ return log_link_debug_errno(link, r, "Could not append IFLA_IPTUN_6RD_PREFIXLEN attribute: %m");
+
+ relay_prefix = ipv4address;
+ (void) in4_addr_mask(&relay_prefix, ipv4masklen);
+ r = sd_netlink_message_append_u32(m, IFLA_IPTUN_6RD_RELAY_PREFIX, relay_prefix.s_addr);
+ if (r < 0)
+ return log_link_debug_errno(link, r, "Could not append IFLA_IPTUN_6RD_RELAY_PREFIX attribute: %m");
+
+ r = sd_netlink_message_append_u16(m, IFLA_IPTUN_6RD_RELAY_PREFIXLEN, ipv4masklen);
+ if (r < 0)
+ return log_link_debug_errno(link, r, "Could not append IFLA_IPTUN_6RD_RELAY_PREFIXLEN attribute: %m");
+
+ r = sd_netlink_message_close_container(m);
+ if (r < 0)
+ return log_link_debug_errno(link, r, "Could not append IFLA_INFO_DATA attribute: %m");
+
+ r = sd_netlink_message_close_container(m);
+ if (r < 0)
+ return log_link_debug_errno(link, r, "Could not append IFLA_LINKINFO attribute: %m");
+
+ r = netlink_call_async(link->manager->rtnl, NULL, m, callback,
+ link_netlink_destroy_callback, link);
+ if (r < 0)
+ return log_link_debug_errno(link, r, "Could not send rtnetlink message: %m");
+
+ link_ref(link);
+
+ return 0;
+}
+
static int netdev_ipip_sit_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
Tunnel *t;
int r;
#include "conf-parser.h"
#include "fou-tunnel.h"
#include "netdev.h"
+#include "networkd-link.h"
typedef enum Ip6TnlMode {
NETDEV_IP6_TNL_MODE_IP6IP6,
uint8_t sixrd_prefixlen;
} Tunnel;
+int dhcp4_pd_create_6rd_tunnel_name(Link *link, char **ret);
+int dhcp4_pd_create_6rd_tunnel(Link *link, link_netlink_message_handler_t callback);
+
DEFINE_NETDEV_CAST(IPIP, Tunnel);
DEFINE_NETDEV_CAST(GRE, Tunnel);
DEFINE_NETDEV_CAST(GRETAP, Tunnel);
#include "networkd-queue.h"
#include "networkd-radv.h"
#include "networkd-route.h"
+#include "networkd-setlink.h"
#include "parse-util.h"
#include "string-util.h"
#include "strv.h"
+#include "tunnel.h"
bool link_dhcp_pd_is_enabled(Link *link) {
assert(link);
return accept_auto;
}
+bool dhcp4_lease_has_pd_prefix(sd_dhcp_lease *lease) {
+ if (!lease)
+ return false;
+
+ return sd_dhcp_lease_get_6rd(lease, NULL, NULL, NULL, NULL, NULL) >= 0;
+}
+
bool dhcp6_lease_has_pd_prefix(sd_dhcp6_lease *lease) {
uint32_t lifetime_preferred_sec, lifetime_valid_sec;
struct in6_addr pd_prefix;
set_clear(uplink->dhcp_pd_prefixes);
}
+void dhcp4_pd_prefix_lost(Link *uplink) {
+ Link *tunnel;
+
+ dhcp_pd_prefix_lost(uplink);
+
+ if (uplink->dhcp4_6rd_tunnel_name &&
+ link_get_by_name(uplink->manager, uplink->dhcp4_6rd_tunnel_name, &tunnel) >= 0)
+ (void) link_remove(tunnel);
+}
+
+static int dhcp4_unreachable_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
+ int r;
+
+ assert(link);
+ assert(link->dhcp4_messages > 0);
+
+ link->dhcp4_messages--;
+
+ r = route_configure_handler_internal(rtnl, m, link, "Failed to set unreachable route for DHCP delegated prefix");
+ if (r <= 0)
+ return r;
+
+ r = dhcp4_check_ready(link);
+ if (r < 0)
+ link_enter_failed(link);
+
+ return 1;
+}
+
static int dhcp6_unreachable_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
int r;
return 0;
}
+static int dhcp4_request_unreachable_route(
+ Link *link,
+ const struct in6_addr *addr,
+ uint8_t prefixlen,
+ usec_t lifetime_usec,
+ const union in_addr_union *server_address) {
+
+ return dhcp_request_unreachable_route(link, addr, prefixlen, lifetime_usec,
+ NETWORK_CONFIG_SOURCE_DHCP4, server_address,
+ &link->dhcp4_messages, dhcp4_unreachable_route_handler);
+}
+
static int dhcp6_request_unreachable_route(
Link *link,
const struct in6_addr *addr,
return 0;
}
+static int dhcp4_pd_request_default_gateway_on_6rd_tunnel(Link *link, const struct in_addr *br_address, usec_t lifetime_usec) {
+ _cleanup_(route_freep) Route *route = NULL;
+ Route *existing;
+ int r;
+
+ assert(link);
+ assert(br_address);
+
+ r = route_new(&route);
+ if (r < 0)
+ return log_link_debug_errno(link, r, "Failed to allocate default gateway for DHCP delegated prefix: %m");
+
+ route->source = NETWORK_CONFIG_SOURCE_DHCP_PD;
+ route->family = AF_INET6;
+ route->gw_family = AF_INET6;
+ route->gw.in6.s6_addr32[3] = br_address->s_addr;
+ route->scope = RT_SCOPE_UNIVERSE;
+ route->protocol = RTPROT_DHCP;
+ route->priority = IP6_RT_PRIO_USER;
+ route->lifetime_usec = lifetime_usec;
+
+ if (route_get(NULL, link, route, &existing) < 0) /* This is a new route. */
+ link->dhcp_pd_configured = false;
+ else
+ route_unmark(existing);
+
+ r = link_request_route(link, TAKE_PTR(route), true, &link->dhcp_pd_messages,
+ dhcp_pd_route_handler, NULL);
+ if (r < 0)
+ return log_link_debug_errno(link, r, "Failed to request default gateway for DHCP delegated prefix: %m");
+
+ return 0;
+}
+
+static void dhcp4_calculate_pd_prefix(
+ const struct in_addr *ipv4address,
+ uint8_t ipv4masklen,
+ const struct in6_addr *sixrd_prefix,
+ uint8_t sixrd_prefixlen,
+ struct in6_addr *ret_pd_prefix,
+ uint8_t *ret_pd_prefixlen) {
+
+ struct in6_addr pd_prefix;
+
+ assert(ipv4address);
+ assert(ipv4masklen <= 32);
+ assert(sixrd_prefix);
+ assert(32 - ipv4masklen + sixrd_prefixlen <= 128);
+ assert(ret_pd_prefix);
+
+ pd_prefix = *sixrd_prefix;
+ for (unsigned i = 0; i < (unsigned) (32 - ipv4masklen); i++)
+ if (ipv4address->s_addr & htobe32(UINT32_C(1) << (32 - ipv4masklen - i - 1)))
+ pd_prefix.s6_addr[(i + sixrd_prefixlen) / 8] |= 1 << (7 - (i + sixrd_prefixlen) % 8);
+
+ *ret_pd_prefix = pd_prefix;
+ if (ret_pd_prefixlen)
+ *ret_pd_prefixlen = 32 - ipv4masklen + sixrd_prefixlen;
+}
+
+static int dhcp4_pd_assign_subnet_prefix(Link *link, Link *uplink) {
+ uint8_t ipv4masklen, sixrd_prefixlen, pd_prefixlen;
+ struct in6_addr sixrd_prefix, pd_prefix;
+ const struct in_addr *br_addresses;
+ struct in_addr ipv4address;
+ uint32_t lifetime_sec;
+ usec_t lifetime_usec;
+ int r;
+
+ assert(link);
+ assert(uplink);
+ assert(uplink->dhcp_lease);
+
+ r = sd_dhcp_lease_get_address(uplink->dhcp_lease, &ipv4address);
+ if (r < 0)
+ return log_link_warning_errno(uplink, r, "Failed to get DHCPv4 address: %m");
+
+ r = sd_dhcp_lease_get_lifetime(uplink->dhcp_lease, &lifetime_sec);
+ if (r < 0)
+ return log_link_warning_errno(uplink, r, "Failed to get lifetime of DHCPv4 lease: %m");
+
+ lifetime_usec = usec_add(lifetime_sec * USEC_PER_SEC, now(clock_boottime_or_monotonic()));
+
+ r = sd_dhcp_lease_get_6rd(uplink->dhcp_lease, &ipv4masklen, &sixrd_prefixlen, &sixrd_prefix, &br_addresses, NULL);
+ if (r < 0)
+ return log_link_warning_errno(uplink, r, "Failed to get 6rd option: %m");
+
+ dhcp4_calculate_pd_prefix(&ipv4address, ipv4masklen, &sixrd_prefix, sixrd_prefixlen, &pd_prefix, &pd_prefixlen);
+
+ if (pd_prefixlen > 64)
+ return 0;
+
+ r = dhcp_pd_prepare(link);
+ if (r <= 0)
+ return r;
+
+ if (streq_ptr(uplink->dhcp4_6rd_tunnel_name, link->ifname)) {
+ r = dhcp_pd_assign_prefix_on_uplink(link, &pd_prefix, pd_prefixlen, lifetime_usec, lifetime_usec);
+ if (r < 0)
+ return r;
+
+ r = dhcp4_pd_request_default_gateway_on_6rd_tunnel(link, &br_addresses[0], lifetime_usec);
+ if (r < 0)
+ return r;
+ } else {
+ r = dhcp_pd_assign_subnet_prefix(link, &pd_prefix, pd_prefixlen, lifetime_usec, lifetime_usec);
+ if (r < 0)
+ return r;
+ }
+
+ return dhcp_pd_finalize(link);
+}
+
+static int dhcp4_pd_6rd_tunnel_create_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
+ int r;
+
+ assert(m);
+ assert(link);
+ assert(link->manager);
+ assert(link->dhcp4_6rd_tunnel_name);
+
+ if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
+ return 0;
+
+ r = sd_netlink_message_get_errno(m);
+ if (r < 0) {
+ log_link_message_warning_errno(link, m, r, "Failed to create 6rd tunnel device");
+ link_enter_failed(link);
+ return 0;
+ }
+
+ return 0;
+}
+
+int dhcp4_pd_prefix_acquired(Link *uplink) {
+ _cleanup_free_ char *tunnel_name = NULL;
+ uint8_t ipv4masklen, sixrd_prefixlen, pd_prefixlen;
+ struct in6_addr sixrd_prefix, pd_prefix;
+ struct in_addr ipv4address;
+ union in_addr_union server_address;
+ uint32_t lifetime_sec;
+ usec_t lifetime_usec;
+ Link *link;
+ int r;
+
+ assert(uplink);
+ assert(uplink->dhcp_lease);
+
+ r = sd_dhcp_lease_get_address(uplink->dhcp_lease, &ipv4address);
+ if (r < 0)
+ return log_link_warning_errno(uplink, r, "Failed to get DHCPv4 address: %m");
+
+ r = sd_dhcp_lease_get_lifetime(uplink->dhcp_lease, &lifetime_sec);
+ if (r < 0)
+ return log_link_warning_errno(uplink, r, "Failed to get lifetime of DHCPv4 lease: %m");
+
+ lifetime_usec = usec_add(lifetime_sec * USEC_PER_SEC, now(clock_boottime_or_monotonic()));
+
+ r = sd_dhcp_lease_get_server_identifier(uplink->dhcp_lease, &server_address.in);
+ if (r < 0)
+ return log_link_warning_errno(uplink, r, "Failed to get server address of DHCPv4 lease: %m");
+
+ r = sd_dhcp_lease_get_6rd(uplink->dhcp_lease, &ipv4masklen, &sixrd_prefixlen, &sixrd_prefix, NULL, NULL);
+ if (r < 0)
+ return log_link_warning_errno(uplink, r, "Failed to get 6rd option: %m");
+
+ /* Calculate PD prefix */
+ dhcp4_calculate_pd_prefix(&ipv4address, ipv4masklen, &sixrd_prefix, sixrd_prefixlen, &pd_prefix, &pd_prefixlen);
+
+ /* Register and log PD prefix */
+ r = dhcp_pd_prefix_add(uplink, &pd_prefix, pd_prefixlen);
+ if (r < 0)
+ return r;
+
+ /* Request unreachable route */
+ r = dhcp4_request_unreachable_route(uplink, &pd_prefix, pd_prefixlen, lifetime_usec, &server_address);
+ if (r < 0)
+ return r;
+
+ /* Generate 6rd SIT tunnel device name. */
+ r = dhcp4_pd_create_6rd_tunnel_name(uplink, &tunnel_name);
+ if (r < 0)
+ return r;
+
+ /* Remove old tunnel device if exists. */
+ if (!streq_ptr(uplink->dhcp4_6rd_tunnel_name, tunnel_name)) {
+ Link *old_tunnel;
+
+ if (uplink->dhcp4_6rd_tunnel_name &&
+ link_get_by_name(uplink->manager, uplink->dhcp4_6rd_tunnel_name, &old_tunnel) >= 0)
+ (void) link_remove(old_tunnel);
+
+ free_and_replace(uplink->dhcp4_6rd_tunnel_name, tunnel_name);
+ }
+
+ /* Create 6rd SIT tunnel device if it does not exist yet. */
+ if (link_get_by_name(uplink->manager, uplink->dhcp4_6rd_tunnel_name, NULL) < 0) {
+ r = dhcp4_pd_create_6rd_tunnel(uplink, dhcp4_pd_6rd_tunnel_create_handler);
+ if (r < 0)
+ return r;
+ }
+
+ /* Then, assign subnet prefixes to downstream interfaces. */
+ HASHMAP_FOREACH(link, uplink->manager->links_by_index) {
+ if (!dhcp_pd_is_uplink(link, uplink, /* accept_auto = */ true))
+ continue;
+
+ r = dhcp4_pd_assign_subnet_prefix(link, uplink);
+ if (r < 0) {
+ /* When failed on the upstream interface (i.e., the case link == uplink),
+ * immediately abort the assignment of the prefixes. As, the all assigned
+ * prefixes will be dropped soon in link_enter_failed(), and it is meaningless
+ * to continue the assignment. */
+ if (link == uplink)
+ return r;
+
+ link_enter_failed(link);
+ }
+ }
+
+ return 0;
+}
+
static int dhcp6_pd_assign_subnet_prefixes(Link *link, Link *uplink) {
usec_t timestamp_usec;
int r;
return 0;
}
+static bool dhcp4_pd_uplink_is_ready(Link *link) {
+ assert(link);
+
+ if (!link->network)
+ return false;
+
+ if (!link->network->dhcp_use_6rd)
+ return false;
+
+ if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
+ return false;
+
+ if (!link->dhcp_client)
+ return false;
+
+ if (sd_dhcp_client_is_running(link->dhcp_client) <= 0)
+ return false;
+
+ if (!link->dhcp_lease)
+ return false;
+
+ return dhcp4_lease_has_pd_prefix(link->dhcp_lease);
+}
+
static bool dhcp6_pd_uplink_is_ready(Link *link) {
assert(link);
return r;
if (uplink) {
- if (!dhcp6_pd_uplink_is_ready(uplink))
- return -EBUSY;
+ if (dhcp4_pd_uplink_is_ready(uplink)) {
+ *ret = uplink;
+ return AF_INET;
+ }
- *ret = uplink;
- return 0;
+ if (dhcp6_pd_uplink_is_ready(uplink)) {
+ *ret = uplink;
+ return AF_INET6;
+ }
+
+ return -EBUSY;
}
HASHMAP_FOREACH(uplink, link->manager->links_by_index) {
- if (!dhcp6_pd_uplink_is_ready(uplink))
- continue;
-
/* Assume that there exists at most one link which acquired delegated prefixes. */
- *ret = uplink;
- return 0;
+ if (dhcp4_pd_uplink_is_ready(uplink)) {
+ *ret = uplink;
+ return AF_INET;
+ }
+
+ if (dhcp6_pd_uplink_is_ready(uplink)) {
+ *ret = uplink;
+ return AF_INET6;
+ }
}
return -ENODEV;
int dhcp_request_prefix_delegation(Link *link) {
Link *uplink;
+ int r;
assert(link);
if (!link_dhcp_pd_is_enabled(link))
return 0;
- if (dhcp_pd_find_uplink(link, &uplink) < 0)
+ r = dhcp_pd_find_uplink(link, &uplink);
+ if (r < 0)
return 0;
- log_link_debug(link, "Requesting subnets of delegated prefixes acquired by %s", uplink->ifname);
- return dhcp6_pd_assign_subnet_prefixes(link, uplink);
+ log_link_debug(link, "Requesting subnets of delegated prefixes acquired by DHCPv%c client on %s",
+ r == AF_INET ? '4' : '6', uplink->ifname);
+
+ return r == AF_INET ?
+ dhcp4_pd_assign_subnet_prefix(link, uplink) :
+ dhcp6_pd_assign_subnet_prefixes(link, uplink);
}
int config_parse_dhcp_pd_subnet_id(
#include <stdbool.h>
+#include "sd-dhcp-lease.h"
#include "sd-dhcp6-lease.h"
#include "conf-parser.h"
bool link_dhcp_pd_is_enabled(Link *link);
bool dhcp_pd_is_uplink(Link *link, Link *target, bool accept_auto);
int dhcp_pd_find_uplink(Link *link, Link **ret);
+bool dhcp4_lease_has_pd_prefix(sd_dhcp_lease *lease);
bool dhcp6_lease_has_pd_prefix(sd_dhcp6_lease *lease);
int dhcp_pd_remove(Link *link, bool only_marked);
int dhcp_request_prefix_delegation(Link *link);
+int dhcp4_pd_prefix_acquired(Link *uplink);
int dhcp6_pd_prefix_acquired(Link *uplink);
void dhcp_pd_prefix_lost(Link *uplink);
+void dhcp4_pd_prefix_lost(Link *uplink);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_pd_subnet_id);
#include "parse-util.h"
#include "network-internal.h"
#include "networkd-address.h"
+#include "networkd-dhcp-prefix-delegation.h"
#include "networkd-dhcp4.h"
#include "networkd-ipv4acd.h"
#include "networkd-link.h"
#include "sysctl-util.h"
static int dhcp4_request_address_and_routes(Link *link, bool announce);
-static int dhcp4_check_ready(Link *link);
void network_adjust_dhcp4(Network *network) {
assert(network);
return dhcp4_check_ready(address->link);
}
-static int dhcp4_check_ready(Link *link) {
+int dhcp4_check_ready(Link *link) {
Address *address;
int r;
assert(link);
assert(link->dhcp_lease);
+ assert(link->network);
log_link_info(link, "DHCP lease lost");
link->dhcp4_configured = false;
+ if (link->network->dhcp_use_6rd &&
+ dhcp4_lease_has_pd_prefix(link->dhcp_lease))
+ dhcp4_pd_prefix_lost(link);
+
k = dhcp4_remove_address_and_routes(link, /* only_marked = */ false);
if (k < 0)
r = k;
}
static int dhcp_lease_renew(sd_dhcp_client *client, Link *link) {
+ _cleanup_(sd_dhcp_lease_unrefp) sd_dhcp_lease *old_lease = NULL;
sd_dhcp_lease *lease;
int r;
assert(link);
+ assert(link->network);
assert(client);
r = sd_dhcp_client_get_lease(client, &lease);
if (r < 0)
return log_link_warning_errno(link, r, "DHCP error: no lease: %m");
- sd_dhcp_lease_unref(link->dhcp_lease);
+ old_lease = TAKE_PTR(link->dhcp_lease);
link->dhcp_lease = sd_dhcp_lease_ref(lease);
link_dirty(link);
+ if (link->network->dhcp_use_6rd) {
+ if (dhcp4_lease_has_pd_prefix(link->dhcp_lease)) {
+ r = dhcp4_pd_prefix_acquired(link);
+ if (r < 0)
+ return log_link_warning_errno(link, r, "Failed to process 6rd option: %m");
+ } else if (dhcp4_lease_has_pd_prefix(old_lease))
+ dhcp4_pd_prefix_lost(link);
+ }
+
return dhcp4_request_address_and_routes(link, false);
}
}
}
+ if (link->network->dhcp_use_6rd &&
+ dhcp4_lease_has_pd_prefix(link->dhcp_lease)) {
+ r = dhcp4_pd_prefix_acquired(link);
+ if (r < 0)
+ return log_link_warning_errno(link, r, "Failed to process 6rd option: %m");
+ }
+
return dhcp4_request_address_and_routes(link, true);
}
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set request flag for timezone: %m");
}
+ if (link->network->dhcp_use_6rd) {
+ r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_6RD);
+ if (r < 0)
+ return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set request flag for 6rd: %m");
+ }
+
SET_FOREACH(request_options, link->network->dhcp_request_options) {
uint32_t option = PTR_TO_UINT32(request_options);
int dhcp4_update_mac(Link *link);
int dhcp4_start(Link *link);
int dhcp4_lease_lost(Link *link);
+int dhcp4_check_ready(Link *link);
int request_process_dhcp4_client(Request *req);
int link_request_dhcp4_client(Link *link);
link->dhcp_server = sd_dhcp_server_unref(link->dhcp_server);
link->dhcp_client = sd_dhcp_client_unref(link->dhcp_client);
link->dhcp_lease = sd_dhcp_lease_unref(link->dhcp_lease);
+ link->dhcp4_6rd_tunnel_name = mfree(link->dhcp4_6rd_tunnel_name);
link->lldp_rx = sd_lldp_rx_unref(link->lldp_rx);
link->lldp_tx = sd_lldp_tx_unref(link->lldp_tx);
bool dhcp4_route_failed:1;
bool dhcp4_route_retrying:1;
bool dhcp4_configured:1;
+ char *dhcp4_6rd_tunnel_name;
sd_ipv4ll *ipv4ll;
bool ipv4ll_address_configured:1;
DHCPv4.SendVendorOption, config_parse_dhcp_send_option, 0, offsetof(Network, dhcp_client_send_vendor_options)
DHCPv4.RouteMTUBytes, config_parse_mtu, AF_INET, offsetof(Network, dhcp_route_mtu)
DHCPv4.FallbackLeaseLifetimeSec, config_parse_dhcp_fallback_lease_lifetime, 0, 0
+DHCPv4.Use6RD, config_parse_bool, 0, offsetof(Network, dhcp_use_6rd)
DHCPv6.UseAddress, config_parse_bool, 0, offsetof(Network, dhcp6_use_address)
DHCPv6.UseDelegatedPrefix, config_parse_bool, 0, offsetof(Network, dhcp6_use_pd_prefix)
DHCPv6.UseDNS, config_parse_dhcp_use_dns, AF_INET6, 0
int dhcp_use_gateway;
bool dhcp_use_timezone;
bool dhcp_use_hostname;
+ bool dhcp_use_6rd;
bool dhcp_send_release;
bool dhcp_send_decline;
DHCPUseDomains dhcp_use_domains;
MUDURL=
RouteMTUBytes=
FallbackLeaseLifetimeSec=
+Use6RD=
[DHCPv6]
UseAddress=
UseDelegatedPrefix=