mirror of
https://github.com/systemd/systemd.git
synced 2024-12-23 21:35:11 +03:00
Merge pull request #22452 from yuwata/network-ipv6ll
network: use sysctl to set IPv6LL address generation mode when the interface is already up
This commit is contained in:
commit
ac7e18be76
@ -93,6 +93,8 @@ sources = files('''
|
||||
networkd-ipv4ll.h
|
||||
networkd-ipv6-proxy-ndp.c
|
||||
networkd-ipv6-proxy-ndp.h
|
||||
networkd-ipv6ll.c
|
||||
networkd-ipv6ll.h
|
||||
networkd-json.c
|
||||
networkd-json.h
|
||||
networkd-link-bus.c
|
||||
|
248
src/network/networkd-ipv6ll.c
Normal file
248
src/network/networkd-ipv6ll.c
Normal file
@ -0,0 +1,248 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include <linux/if.h>
|
||||
#include <linux/if_arp.h>
|
||||
|
||||
#include "in-addr-util.h"
|
||||
#include "networkd-address.h"
|
||||
#include "networkd-ipv6ll.h"
|
||||
#include "networkd-link.h"
|
||||
#include "networkd-network.h"
|
||||
#include "networkd-util.h"
|
||||
#include "socket-util.h"
|
||||
#include "string-table.h"
|
||||
#include "strv.h"
|
||||
#include "sysctl-util.h"
|
||||
|
||||
bool link_ipv6ll_enabled(Link *link) {
|
||||
assert(link);
|
||||
|
||||
if (!socket_ipv6_is_supported())
|
||||
return false;
|
||||
|
||||
if (link->flags & IFF_LOOPBACK)
|
||||
return false;
|
||||
|
||||
if (!link->network)
|
||||
return false;
|
||||
|
||||
if (link->iftype == ARPHRD_CAN)
|
||||
return false;
|
||||
|
||||
if (STRPTR_IN_SET(link->kind, "vrf", "wireguard", "ipip", "gre", "sit", "vti", "nlmon"))
|
||||
return false;
|
||||
|
||||
if (link->network->bond)
|
||||
return false;
|
||||
|
||||
return link->network->link_local & ADDRESS_FAMILY_IPV6;
|
||||
}
|
||||
|
||||
bool link_may_have_ipv6ll(Link *link) {
|
||||
assert(link);
|
||||
|
||||
/*
|
||||
* This is equivalent to link_ipv6ll_enabled() for non-WireGuard interfaces.
|
||||
*
|
||||
* For WireGuard interface, the kernel does not assign any IPv6LL addresses, but we can assign
|
||||
* it manually. It is necessary to set an IPv6LL address manually to run NDisc or RADV on
|
||||
* WireGuard interface. Note, also Multicast=yes must be set. See #17380.
|
||||
*
|
||||
* TODO: May be better to introduce GenerateIPv6LinkLocalAddress= setting, and use algorithms
|
||||
* used in networkd-address-generation.c
|
||||
*/
|
||||
|
||||
if (link_ipv6ll_enabled(link))
|
||||
return true;
|
||||
|
||||
/* IPv6LL address can be manually assigned on WireGuard interface. */
|
||||
if (streq_ptr(link->kind, "wireguard")) {
|
||||
Address *a;
|
||||
|
||||
if (!link->network)
|
||||
return false;
|
||||
|
||||
ORDERED_HASHMAP_FOREACH(a, link->network->addresses_by_section) {
|
||||
if (a->family != AF_INET6)
|
||||
continue;
|
||||
if (in6_addr_is_set(&a->in_addr_peer.in6))
|
||||
continue;
|
||||
if (in6_addr_is_link_local(&a->in_addr.in6))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
IPv6LinkLocalAddressGenMode link_get_ipv6ll_addrgen_mode(Link *link) {
|
||||
assert(link);
|
||||
|
||||
if (!link_ipv6ll_enabled(link))
|
||||
return IPV6_LINK_LOCAL_ADDRESSS_GEN_MODE_NONE;
|
||||
|
||||
if (link->network->ipv6ll_address_gen_mode >= 0)
|
||||
return link->network->ipv6ll_address_gen_mode;
|
||||
|
||||
if (in6_addr_is_set(&link->network->ipv6ll_stable_secret))
|
||||
return IPV6_LINK_LOCAL_ADDRESSS_GEN_MODE_STABLE_PRIVACY;
|
||||
|
||||
return IPV6_LINK_LOCAL_ADDRESSS_GEN_MODE_EUI64;
|
||||
}
|
||||
|
||||
int ipv6ll_addrgen_mode_fill_message(sd_netlink_message *message, IPv6LinkLocalAddressGenMode mode) {
|
||||
int r;
|
||||
|
||||
assert(message);
|
||||
assert(mode >= 0 && mode < _IPV6_LINK_LOCAL_ADDRESS_GEN_MODE_MAX);
|
||||
|
||||
r = sd_netlink_message_open_container(message, IFLA_AF_SPEC);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_netlink_message_open_container(message, AF_INET6);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_netlink_message_append_u8(message, IFLA_INET6_ADDR_GEN_MODE, mode);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_netlink_message_close_container(message);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_netlink_message_close_container(message);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int link_update_ipv6ll_addrgen_mode(Link *link, sd_netlink_message *message) {
|
||||
uint8_t mode;
|
||||
int family, r;
|
||||
|
||||
assert(link);
|
||||
assert(message);
|
||||
|
||||
r = sd_rtnl_message_get_family(message, &family);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (family != AF_UNSPEC)
|
||||
return 0;
|
||||
|
||||
r = sd_netlink_message_enter_container(message, IFLA_AF_SPEC);
|
||||
if (r == -ENODATA)
|
||||
return 0;
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_netlink_message_enter_container(message, AF_INET6);
|
||||
if (r == -ENODATA)
|
||||
return sd_netlink_message_exit_container(message);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
mode = (uint8_t) link->ipv6ll_address_gen_mode;
|
||||
r = sd_netlink_message_read_u8(message, IFLA_INET6_ADDR_GEN_MODE, &mode);
|
||||
if (r < 0 && r != -ENODATA)
|
||||
return r;
|
||||
|
||||
r = sd_netlink_message_exit_container(message);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_netlink_message_exit_container(message);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (mode == (uint8_t) link->ipv6ll_address_gen_mode)
|
||||
return 0;
|
||||
|
||||
if (mode >= _IPV6_LINK_LOCAL_ADDRESS_GEN_MODE_MAX) {
|
||||
log_link_debug(link, "Received invalid IPv6 link-local address generation mode (%u), ignoring.", mode);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (link->ipv6ll_address_gen_mode < 0)
|
||||
log_link_debug(link, "Saved IPv6 link-local address generation mode: %s",
|
||||
ipv6_link_local_address_gen_mode_to_string(mode));
|
||||
else
|
||||
log_link_debug(link, "IPv6 link-local address generation mode is changed: %s -> %s",
|
||||
ipv6_link_local_address_gen_mode_to_string(link->ipv6ll_address_gen_mode),
|
||||
ipv6_link_local_address_gen_mode_to_string(mode));
|
||||
|
||||
link->ipv6ll_address_gen_mode = mode;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define STABLE_SECRET_APP_ID_1 SD_ID128_MAKE(aa,05,1d,94,43,68,45,07,b9,73,f1,e8,e4,b7,34,52)
|
||||
#define STABLE_SECRET_APP_ID_2 SD_ID128_MAKE(52,c4,40,a0,9f,2f,48,58,a9,3a,f6,29,25,ba,7a,7d)
|
||||
|
||||
int link_set_ipv6ll_stable_secret(Link *link) {
|
||||
_cleanup_free_ char *str = NULL;
|
||||
struct in6_addr a;
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
assert(link->network);
|
||||
|
||||
if (link->network->ipv6ll_address_gen_mode != IPV6_LINK_LOCAL_ADDRESSS_GEN_MODE_STABLE_PRIVACY)
|
||||
return 0;
|
||||
|
||||
if (in6_addr_is_set(&link->network->ipv6ll_stable_secret))
|
||||
a = link->network->ipv6ll_stable_secret;
|
||||
else {
|
||||
sd_id128_t key;
|
||||
le64_t v;
|
||||
|
||||
/* Generate a stable secret address from machine-ID and the interface name. */
|
||||
|
||||
r = sd_id128_get_machine_app_specific(STABLE_SECRET_APP_ID_1, &key);
|
||||
if (r < 0)
|
||||
return log_link_debug_errno(link, r, "Failed to generate key: %m");
|
||||
|
||||
v = htole64(siphash24_string(link->ifname, key.bytes));
|
||||
memcpy(a.s6_addr, &v, sizeof(v));
|
||||
|
||||
r = sd_id128_get_machine_app_specific(STABLE_SECRET_APP_ID_2, &key);
|
||||
if (r < 0)
|
||||
return log_link_debug_errno(link, r, "Failed to generate key: %m");
|
||||
|
||||
v = htole64(siphash24_string(link->ifname, key.bytes));
|
||||
assert_cc(sizeof(v) * 2 == sizeof(a.s6_addr));
|
||||
memcpy(a.s6_addr + sizeof(v), &v, sizeof(v));
|
||||
}
|
||||
|
||||
r = in6_addr_to_string(&a, &str);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return sysctl_write_ip_property(AF_INET6, link->ifname, "stable_secret", str);
|
||||
}
|
||||
|
||||
int link_set_ipv6ll_addrgen_mode(Link *link, IPv6LinkLocalAddressGenMode mode) {
|
||||
assert(link);
|
||||
assert(mode >= 0 && mode < _IPV6_LINK_LOCAL_ADDRESS_GEN_MODE_MAX);
|
||||
|
||||
if (mode == link->ipv6ll_address_gen_mode)
|
||||
return 0;
|
||||
|
||||
return sysctl_write_ip_property_uint32(AF_INET6, link->ifname, "addr_gen_mode", mode);
|
||||
}
|
||||
|
||||
static const char* const ipv6_link_local_address_gen_mode_table[_IPV6_LINK_LOCAL_ADDRESS_GEN_MODE_MAX] = {
|
||||
[IPV6_LINK_LOCAL_ADDRESSS_GEN_MODE_EUI64] = "eui64",
|
||||
[IPV6_LINK_LOCAL_ADDRESSS_GEN_MODE_NONE] = "none",
|
||||
[IPV6_LINK_LOCAL_ADDRESSS_GEN_MODE_STABLE_PRIVACY] = "stable-privacy",
|
||||
[IPV6_LINK_LOCAL_ADDRESSS_GEN_MODE_RANDOM] = "random",
|
||||
};
|
||||
|
||||
DEFINE_STRING_TABLE_LOOKUP(ipv6_link_local_address_gen_mode, IPv6LinkLocalAddressGenMode);
|
||||
DEFINE_CONFIG_PARSE_ENUM(
|
||||
config_parse_ipv6_link_local_address_gen_mode,
|
||||
ipv6_link_local_address_gen_mode,
|
||||
IPv6LinkLocalAddressGenMode,
|
||||
"Failed to parse IPv6 link local address generation mode");
|
37
src/network/networkd-ipv6ll.h
Normal file
37
src/network/networkd-ipv6ll.h
Normal file
@ -0,0 +1,37 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
#include <errno.h>
|
||||
#include <linux/if_link.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "sd-netlink.h"
|
||||
|
||||
#include "conf-parser.h"
|
||||
#include "macro.h"
|
||||
|
||||
typedef struct Link Link;
|
||||
|
||||
typedef enum IPv6LinkLocalAddressGenMode {
|
||||
IPV6_LINK_LOCAL_ADDRESSS_GEN_MODE_EUI64 = IN6_ADDR_GEN_MODE_EUI64,
|
||||
IPV6_LINK_LOCAL_ADDRESSS_GEN_MODE_NONE = IN6_ADDR_GEN_MODE_NONE,
|
||||
IPV6_LINK_LOCAL_ADDRESSS_GEN_MODE_STABLE_PRIVACY = IN6_ADDR_GEN_MODE_STABLE_PRIVACY,
|
||||
IPV6_LINK_LOCAL_ADDRESSS_GEN_MODE_RANDOM = IN6_ADDR_GEN_MODE_RANDOM,
|
||||
_IPV6_LINK_LOCAL_ADDRESS_GEN_MODE_MAX,
|
||||
_IPV6_LINK_LOCAL_ADDRESS_GEN_MODE_INVALID = -EINVAL,
|
||||
} IPv6LinkLocalAddressGenMode;
|
||||
|
||||
bool link_ipv6ll_enabled(Link *link);
|
||||
bool link_may_have_ipv6ll(Link *link);
|
||||
|
||||
IPv6LinkLocalAddressGenMode link_get_ipv6ll_addrgen_mode(Link *link);
|
||||
int ipv6ll_addrgen_mode_fill_message(sd_netlink_message *message, IPv6LinkLocalAddressGenMode mode);
|
||||
int link_update_ipv6ll_addrgen_mode(Link *link, sd_netlink_message *message);
|
||||
|
||||
int link_set_ipv6ll_stable_secret(Link *link);
|
||||
int link_set_ipv6ll_addrgen_mode(Link *link, IPv6LinkLocalAddressGenMode mode);
|
||||
|
||||
const char* ipv6_link_local_address_gen_mode_to_string(IPv6LinkLocalAddressGenMode s) _const_;
|
||||
IPv6LinkLocalAddressGenMode ipv6_link_local_address_gen_mode_from_string(const char *s) _pure_;
|
||||
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_ipv6_link_local_address_gen_mode);
|
@ -105,67 +105,6 @@ bool link_ipv4ll_enabled(Link *link) {
|
||||
return link->network->link_local & ADDRESS_FAMILY_IPV4;
|
||||
}
|
||||
|
||||
bool link_ipv6ll_enabled(Link *link) {
|
||||
assert(link);
|
||||
|
||||
if (!socket_ipv6_is_supported())
|
||||
return false;
|
||||
|
||||
if (link->flags & IFF_LOOPBACK)
|
||||
return false;
|
||||
|
||||
if (!link->network)
|
||||
return false;
|
||||
|
||||
if (link->iftype == ARPHRD_CAN)
|
||||
return false;
|
||||
|
||||
if (STRPTR_IN_SET(link->kind, "vrf", "wireguard", "ipip", "gre", "sit", "vti", "nlmon"))
|
||||
return false;
|
||||
|
||||
if (link->network->bond)
|
||||
return false;
|
||||
|
||||
return link->network->link_local & ADDRESS_FAMILY_IPV6;
|
||||
}
|
||||
|
||||
bool link_may_have_ipv6ll(Link *link) {
|
||||
assert(link);
|
||||
|
||||
/*
|
||||
* This is equivalent to link_ipv6ll_enabled() for non-WireGuard interfaces.
|
||||
*
|
||||
* For WireGuard interface, the kernel does not assign any IPv6LL addresses, but we can assign
|
||||
* it manually. It is necessary to set an IPv6LL address manually to run NDisc or RADV on
|
||||
* WireGuard interface. Note, also Multicast=yes must be set. See #17380.
|
||||
*
|
||||
* TODO: May be better to introduce GenerateIPv6LinkLocalAddress= setting, and use algorithms
|
||||
* used in networkd-address-generation.c
|
||||
*/
|
||||
|
||||
if (link_ipv6ll_enabled(link))
|
||||
return true;
|
||||
|
||||
/* IPv6LL address can be manually assigned on WireGuard interface. */
|
||||
if (streq_ptr(link->kind, "wireguard")) {
|
||||
Address *a;
|
||||
|
||||
if (!link->network)
|
||||
return false;
|
||||
|
||||
ORDERED_HASHMAP_FOREACH(a, link->network->addresses_by_section) {
|
||||
if (a->family != AF_INET6)
|
||||
continue;
|
||||
if (in6_addr_is_set(&a->in_addr_peer.in6))
|
||||
continue;
|
||||
if (in6_addr_is_link_local(&a->in_addr.in6))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool link_ipv6_enabled(Link *link) {
|
||||
assert(link);
|
||||
|
||||
@ -2377,6 +2316,10 @@ static int link_update(Link *link, sd_netlink_message *message) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = link_update_ipv6ll_addrgen_mode(link, message);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return link_update_flags(link, message);
|
||||
}
|
||||
|
||||
@ -2450,6 +2393,8 @@ static int link_new(Manager *manager, sd_netlink_message *message, Link **ret) {
|
||||
.ifname = TAKE_PTR(ifname),
|
||||
.kind = TAKE_PTR(kind),
|
||||
|
||||
.ipv6ll_address_gen_mode = _IPV6_LINK_LOCAL_ADDRESS_GEN_MODE_INVALID,
|
||||
|
||||
.state_file = TAKE_PTR(state_file),
|
||||
.lease_file = TAKE_PTR(lease_file),
|
||||
.lldp_file = TAKE_PTR(lldp_file),
|
||||
@ -2569,7 +2514,7 @@ int manager_rtnl_process_link(sd_netlink *rtnl, sd_netlink_message *message, Man
|
||||
/* netdev exists, so make sure the ifindex matches */
|
||||
r = netdev_set_ifindex(netdev, message);
|
||||
if (r < 0) {
|
||||
log_warning_errno(r, "Could not process new link message for netdev, ignoring: %m");
|
||||
log_netdev_warning_errno(netdev, r, "Could not process new link message for netdev, ignoring: %m");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@ -2584,32 +2529,30 @@ int manager_rtnl_process_link(sd_netlink *rtnl, sd_netlink_message *message, Man
|
||||
|
||||
r = link_update(link, message);
|
||||
if (r < 0) {
|
||||
log_warning_errno(r, "Could not process link message: %m");
|
||||
log_link_warning_errno(link, r, "Could not process link message: %m");
|
||||
link_enter_failed(link);
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = link_check_initialized(link);
|
||||
if (r < 0) {
|
||||
log_warning_errno(r, "Failed to check link is initialized: %m");
|
||||
log_link_warning_errno(link, r, "Failed to check link is initialized: %m");
|
||||
link_enter_failed(link);
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
r = link_update(link, message);
|
||||
if (r < 0) {
|
||||
log_warning_errno(r, "Could not process link message: %m");
|
||||
log_link_warning_errno(link, r, "Could not process link message: %m");
|
||||
link_enter_failed(link);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case RTM_DELLINK:
|
||||
link_drop(link);
|
||||
netdev_drop(netdev);
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "log-link.h"
|
||||
#include "netif-util.h"
|
||||
#include "network-util.h"
|
||||
#include "networkd-ipv6ll.h"
|
||||
#include "networkd-util.h"
|
||||
#include "ordered-set.h"
|
||||
#include "resolve-util.h"
|
||||
@ -67,6 +68,9 @@ typedef struct Link {
|
||||
sd_device *sd_device;
|
||||
char *driver;
|
||||
|
||||
/* link local addressing */
|
||||
IPv6LinkLocalAddressGenMode ipv6ll_address_gen_mode;
|
||||
|
||||
/* wlan */
|
||||
enum nl80211_iftype wlan_iftype;
|
||||
char *ssid;
|
||||
@ -220,8 +224,6 @@ static inline bool link_has_carrier(Link *link) {
|
||||
}
|
||||
|
||||
bool link_ipv6_enabled(Link *link);
|
||||
bool link_ipv6ll_enabled(Link *link);
|
||||
bool link_may_have_ipv6ll(Link *link);
|
||||
int link_ipv6ll_gained(Link *link);
|
||||
|
||||
bool link_ipv4ll_enabled(Link *link);
|
||||
|
@ -22,6 +22,7 @@ _Pragma("GCC diagnostic ignored \"-Wimplicit-fallthrough\"")
|
||||
#include "networkd-dhcp6.h"
|
||||
#include "networkd-ipv4ll.h"
|
||||
#include "networkd-ipv6-proxy-ndp.h"
|
||||
#include "networkd-ipv6ll.h"
|
||||
#include "networkd-lldp-tx.h"
|
||||
#include "networkd-ndisc.h"
|
||||
#include "networkd-network.h"
|
||||
|
@ -1386,16 +1386,6 @@ static const char* const keep_configuration_table[_KEEP_CONFIGURATION_MAX] = {
|
||||
|
||||
DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(keep_configuration, KeepConfiguration, KEEP_CONFIGURATION_YES);
|
||||
|
||||
static const char* const ipv6_link_local_address_gen_mode_table[_IPV6_LINK_LOCAL_ADDRESS_GEN_MODE_MAX] = {
|
||||
[IPV6_LINK_LOCAL_ADDRESSS_GEN_MODE_EUI64] = "eui64",
|
||||
[IPV6_LINK_LOCAL_ADDRESSS_GEN_MODE_NONE] = "none",
|
||||
[IPV6_LINK_LOCAL_ADDRESSS_GEN_MODE_STABLE_PRIVACY] = "stable-privacy",
|
||||
[IPV6_LINK_LOCAL_ADDRESSS_GEN_MODE_RANDOM] = "random",
|
||||
};
|
||||
|
||||
DEFINE_STRING_TABLE_LOOKUP(ipv6_link_local_address_gen_mode, IPv6LinkLocalAddressGenMode);
|
||||
DEFINE_CONFIG_PARSE_ENUM(config_parse_ipv6_link_local_address_gen_mode, ipv6_link_local_address_gen_mode, IPv6LinkLocalAddressGenMode, "Failed to parse IPv6 link local address generation mode");
|
||||
|
||||
static const char* const activation_policy_table[_ACTIVATION_POLICY_MAX] = {
|
||||
[ACTIVATION_POLICY_UP] = "up",
|
||||
[ACTIVATION_POLICY_ALWAYS_UP] = "always-up",
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "networkd-dhcp-common.h"
|
||||
#include "networkd-dhcp4.h"
|
||||
#include "networkd-dhcp6.h"
|
||||
#include "networkd-ipv6ll.h"
|
||||
#include "networkd-lldp-rx.h"
|
||||
#include "networkd-ndisc.h"
|
||||
#include "networkd-radv.h"
|
||||
@ -38,15 +39,6 @@ typedef enum KeepConfiguration {
|
||||
_KEEP_CONFIGURATION_INVALID = -EINVAL,
|
||||
} KeepConfiguration;
|
||||
|
||||
typedef enum IPv6LinkLocalAddressGenMode {
|
||||
IPV6_LINK_LOCAL_ADDRESSS_GEN_MODE_EUI64 = IN6_ADDR_GEN_MODE_EUI64,
|
||||
IPV6_LINK_LOCAL_ADDRESSS_GEN_MODE_NONE = IN6_ADDR_GEN_MODE_NONE,
|
||||
IPV6_LINK_LOCAL_ADDRESSS_GEN_MODE_STABLE_PRIVACY = IN6_ADDR_GEN_MODE_STABLE_PRIVACY,
|
||||
IPV6_LINK_LOCAL_ADDRESSS_GEN_MODE_RANDOM = IN6_ADDR_GEN_MODE_RANDOM,
|
||||
_IPV6_LINK_LOCAL_ADDRESS_GEN_MODE_MAX,
|
||||
_IPV6_LINK_LOCAL_ADDRESS_GEN_MODE_INVALID = -EINVAL,
|
||||
} IPv6LinkLocalAddressGenMode;
|
||||
|
||||
typedef enum ActivationPolicy {
|
||||
ACTIVATION_POLICY_UP,
|
||||
ACTIVATION_POLICY_ALWAYS_UP,
|
||||
@ -386,7 +378,6 @@ CONFIG_PARSER_PROTOTYPE(config_parse_ntp);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_required_for_online);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_required_family_for_online);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_keep_configuration);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_ipv6_link_local_address_gen_mode);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_activation_policy);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_link_group);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_ignore_carrier_loss);
|
||||
@ -396,8 +387,5 @@ const struct ConfigPerfItem* network_network_gperf_lookup(const char *key, GPERF
|
||||
const char* keep_configuration_to_string(KeepConfiguration i) _const_;
|
||||
KeepConfiguration keep_configuration_from_string(const char *s) _pure_;
|
||||
|
||||
const char* ipv6_link_local_address_gen_mode_to_string(IPv6LinkLocalAddressGenMode s) _const_;
|
||||
IPv6LinkLocalAddressGenMode ipv6_link_local_address_gen_mode_from_string(const char *s) _pure_;
|
||||
|
||||
const char* activation_policy_to_string(ActivationPolicy i) _const_;
|
||||
ActivationPolicy activation_policy_from_string(const char *s) _pure_;
|
||||
|
@ -228,23 +228,7 @@ static int link_configure_fill_message(
|
||||
|
||||
switch (op) {
|
||||
case SET_LINK_ADDRESS_GENERATION_MODE:
|
||||
r = sd_netlink_message_open_container(req, IFLA_AF_SPEC);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_netlink_message_open_container(req, AF_INET6);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_netlink_message_append_u8(req, IFLA_INET6_ADDR_GEN_MODE, PTR_TO_UINT8(userdata));
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_netlink_message_close_container(req);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_netlink_message_close_container(req);
|
||||
r = ipv6ll_addrgen_mode_fill_message(req, PTR_TO_UINT8(userdata));
|
||||
if (r < 0)
|
||||
return r;
|
||||
break;
|
||||
@ -695,8 +679,8 @@ static int link_request_set_link(
|
||||
}
|
||||
|
||||
int link_request_to_set_addrgen_mode(Link *link) {
|
||||
IPv6LinkLocalAddressGenMode mode;
|
||||
Request *req;
|
||||
uint8_t mode;
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
@ -705,14 +689,23 @@ int link_request_to_set_addrgen_mode(Link *link) {
|
||||
if (!socket_ipv6_is_supported())
|
||||
return 0;
|
||||
|
||||
if (!link_ipv6ll_enabled(link))
|
||||
mode = IN6_ADDR_GEN_MODE_NONE;
|
||||
else if (link->network->ipv6ll_address_gen_mode >= 0)
|
||||
mode = link->network->ipv6ll_address_gen_mode;
|
||||
else if (in6_addr_is_set(&link->network->ipv6ll_stable_secret))
|
||||
mode = IN6_ADDR_GEN_MODE_STABLE_PRIVACY;
|
||||
else
|
||||
mode = IN6_ADDR_GEN_MODE_EUI64;
|
||||
mode = link_get_ipv6ll_addrgen_mode(link);
|
||||
|
||||
if (mode == link->ipv6ll_address_gen_mode)
|
||||
return 0;
|
||||
|
||||
/* If the link is already up, then changing the mode by netlink does not take effect until the
|
||||
* link goes down. Hence, we need to reset the interface. However, setting the mode by sysctl
|
||||
* does not need that. Let's use the sysctl interface when the link is already up.
|
||||
* See also issue #22424. */
|
||||
if (mode != IPV6_LINK_LOCAL_ADDRESSS_GEN_MODE_NONE &&
|
||||
FLAGS_SET(link->flags, IFF_UP)) {
|
||||
r = link_set_ipv6ll_addrgen_mode(link, mode);
|
||||
if (r < 0)
|
||||
log_link_warning_errno(link, r, "Cannot set IPv6 address generation mode, ignoring: %m");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = link_request_set_link(link, SET_LINK_ADDRESS_GENERATION_MODE, link_set_addrgen_mode_handler, &req);
|
||||
if (r < 0)
|
||||
|
@ -11,9 +11,6 @@
|
||||
#include "string-table.h"
|
||||
#include "sysctl-util.h"
|
||||
|
||||
#define STABLE_SECRET_APP_ID_1 SD_ID128_MAKE(aa,05,1d,94,43,68,45,07,b9,73,f1,e8,e4,b7,34,52)
|
||||
#define STABLE_SECRET_APP_ID_2 SD_ID128_MAKE(52,c4,40,a0,9f,2f,48,58,a9,3a,f6,29,25,ba,7a,7d)
|
||||
|
||||
static int link_update_ipv6_sysctl(Link *link) {
|
||||
assert(link);
|
||||
|
||||
@ -214,48 +211,6 @@ int link_set_ipv6_mtu(Link *link) {
|
||||
return sysctl_write_ip_property_uint32(AF_INET6, link->ifname, "mtu", mtu);
|
||||
}
|
||||
|
||||
static int link_set_ipv6ll_stable_secret(Link *link) {
|
||||
_cleanup_free_ char *str = NULL;
|
||||
struct in6_addr a;
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
assert(link->network);
|
||||
|
||||
if (link->network->ipv6ll_address_gen_mode != IPV6_LINK_LOCAL_ADDRESSS_GEN_MODE_STABLE_PRIVACY)
|
||||
return 0;
|
||||
|
||||
if (in6_addr_is_set(&link->network->ipv6ll_stable_secret))
|
||||
a = link->network->ipv6ll_stable_secret;
|
||||
else {
|
||||
sd_id128_t key;
|
||||
le64_t v;
|
||||
|
||||
/* Generate a stable secret address from machine-ID and the interface name. */
|
||||
|
||||
r = sd_id128_get_machine_app_specific(STABLE_SECRET_APP_ID_1, &key);
|
||||
if (r < 0)
|
||||
return log_link_debug_errno(link, r, "Failed to generate key: %m");
|
||||
|
||||
v = htole64(siphash24_string(link->ifname, key.bytes));
|
||||
memcpy(a.s6_addr, &v, sizeof(v));
|
||||
|
||||
r = sd_id128_get_machine_app_specific(STABLE_SECRET_APP_ID_2, &key);
|
||||
if (r < 0)
|
||||
return log_link_debug_errno(link, r, "Failed to generate key: %m");
|
||||
|
||||
v = htole64(siphash24_string(link->ifname, key.bytes));
|
||||
assert_cc(sizeof(v) * 2 == sizeof(a.s6_addr));
|
||||
memcpy(a.s6_addr + sizeof(v), &v, sizeof(v));
|
||||
}
|
||||
|
||||
r = in6_addr_to_string(&a, &str);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return sysctl_write_ip_property(AF_INET6, link->ifname, "stable_secret", str);
|
||||
}
|
||||
|
||||
static int link_set_ipv4_accept_local(Link *link) {
|
||||
assert(link);
|
||||
|
||||
|
@ -2952,22 +2952,35 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities):
|
||||
self.assertEqual(read_ipv6_sysctl_attr('test1', 'addr_gen_mode'), '2')
|
||||
self.assertEqual(read_ipv6_sysctl_attr('dummy98', 'addr_gen_mode'), '1')
|
||||
|
||||
def test_link_local_addressing_remove_ipv6ll(self):
|
||||
def test_link_local_addressing_ipv6ll(self):
|
||||
copy_unit_to_networkd_unit_path('26-link-local-addressing-ipv6.network', '12-dummy.netdev')
|
||||
start_networkd()
|
||||
self.wait_online(['dummy98:degraded'])
|
||||
|
||||
# An IPv6LL address exists by default.
|
||||
output = check_output('ip address show dev dummy98')
|
||||
print(output)
|
||||
self.assertRegex(output, 'inet6 .* scope link')
|
||||
|
||||
copy_unit_to_networkd_unit_path('25-link-local-addressing-no.network')
|
||||
restart_networkd(1)
|
||||
check_output(*networkctl_cmd, 'reload', env=env)
|
||||
time.sleep(1)
|
||||
self.wait_online(['dummy98:carrier'])
|
||||
|
||||
# Check if the IPv6LL address is removed.
|
||||
output = check_output('ip address show dev dummy98')
|
||||
print(output)
|
||||
self.assertNotRegex(output, 'inet6* .* scope link')
|
||||
self.assertNotRegex(output, 'inet6 .* scope link')
|
||||
|
||||
remove_unit_from_networkd_path(['25-link-local-addressing-no.network'])
|
||||
check_output(*networkctl_cmd, 'reload', env=env)
|
||||
time.sleep(1)
|
||||
self.wait_online(['dummy98:degraded'])
|
||||
|
||||
# Check if a new IPv6LL address is assigned.
|
||||
output = check_output('ip address show dev dummy98')
|
||||
print(output)
|
||||
self.assertRegex(output, 'inet6 .* scope link')
|
||||
|
||||
def test_sysctl(self):
|
||||
copy_unit_to_networkd_unit_path('25-sysctl.network', '12-dummy.netdev')
|
||||
|
Loading…
Reference in New Issue
Block a user