mirror of
https://github.com/systemd/systemd.git
synced 2024-12-31 21:18:09 +03:00
parent
dbdcaca3ab
commit
e49bad0179
18
network/80-6rd-tunnel.network
Normal file
18
network/80-6rd-tunnel.network
Normal 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
|
@ -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',
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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(
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -128,6 +128,7 @@ SendDecline=
|
||||
MUDURL=
|
||||
RouteMTUBytes=
|
||||
FallbackLeaseLifetimeSec=
|
||||
Use6RD=
|
||||
[DHCPv6]
|
||||
UseAddress=
|
||||
UseDelegatedPrefix=
|
||||
|
Loading…
Reference in New Issue
Block a user