1
0
mirror of https://github.com/systemd/systemd synced 2024-07-09 04:26:06 +00:00

network: dhcp-pd: add 6rd support

Closes #19152.
This commit is contained in:
Yu Watanabe 2021-12-06 01:35:55 +09:00
parent dbdcaca3ab
commit e49bad0179
13 changed files with 534 additions and 16 deletions

View File

@ -0,0 +1,18 @@
# 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

View File

@ -1,7 +1,8 @@
# 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',

View File

@ -8,9 +8,12 @@
#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"
@ -29,6 +32,146 @@ static const char* const ip6tnl_mode_table[_NETDEV_IP6_TNL_MODE_MAX] = {
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;

View File

@ -6,6 +6,7 @@
#include "conf-parser.h"
#include "fou-tunnel.h"
#include "netdev.h"
#include "networkd-link.h"
typedef enum Ip6TnlMode {
NETDEV_IP6_TNL_MODE_IP6IP6,
@ -60,6 +61,9 @@ typedef struct Tunnel {
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);

View File

@ -15,9 +15,11 @@
#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);
@ -49,6 +51,13 @@ bool dhcp_pd_is_uplink(Link *link, Link *target, bool accept_auto) {
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;
@ -679,6 +688,35 @@ void dhcp_pd_prefix_lost(Link *uplink) {
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;
@ -759,6 +797,18 @@ static int dhcp_request_unreachable_route(
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,
@ -807,6 +857,229 @@ static int dhcp_pd_prefix_add(Link *link, const struct in6_addr *prefix, uint8_t
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;
@ -922,6 +1195,30 @@ int dhcp6_pd_prefix_acquired(Link *uplink) {
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);
@ -965,20 +1262,30 @@ int dhcp_pd_find_uplink(Link *link, Link **ret) {
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;
@ -986,17 +1293,23 @@ int dhcp_pd_find_uplink(Link *link, Link **ret) {
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(

View File

@ -3,6 +3,7 @@
#include <stdbool.h>
#include "sd-dhcp-lease.h"
#include "sd-dhcp6-lease.h"
#include "conf-parser.h"
@ -12,10 +13,13 @@ typedef struct Link Link;
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);

View File

@ -12,6 +12,7 @@
#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"
@ -27,7 +28,6 @@
#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);
@ -119,7 +119,7 @@ static int dhcp4_address_ready_callback(Address *address) {
return dhcp4_check_ready(address->link);
}
static int dhcp4_check_ready(Link *link) {
int dhcp4_check_ready(Link *link) {
Address *address;
int r;
@ -789,11 +789,16 @@ int dhcp4_lease_lost(Link *link) {
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;
@ -964,20 +969,31 @@ static int dhcp4_request_address_and_routes(Link *link, bool announce) {
}
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);
}
@ -1043,6 +1059,13 @@ static int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) {
}
}
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);
}
@ -1439,6 +1462,12 @@ static int dhcp4_configure(Link *link) {
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);

View File

@ -23,6 +23,7 @@ void network_adjust_dhcp4(Network *network);
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);

View File

@ -208,6 +208,7 @@ static void link_free_engines(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);

View File

@ -114,6 +114,7 @@ typedef struct Link {
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;

View File

@ -240,6 +240,7 @@ DHCPv4.SendOption, config_parse_dhcp_send_option,
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

View File

@ -153,6 +153,7 @@ struct Network {
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;

View File

@ -128,6 +128,7 @@ SendDecline=
MUDURL=
RouteMTUBytes=
FallbackLeaseLifetimeSec=
Use6RD=
[DHCPv6]
UseAddress=
UseDelegatedPrefix=