mirror of
https://github.com/systemd/systemd.git
synced 2024-12-22 17:35:35 +03:00
Merge pull request #11423 from ssahani/issue-9890
networkd: honour LinkLocalAddressing
This commit is contained in:
commit
eb80dbd24b
@ -1763,6 +1763,84 @@ bool link_has_carrier(Link *link) {
|
||||
return false;
|
||||
}
|
||||
|
||||
static int link_address_genmode_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
|
||||
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
|
||||
return 1;
|
||||
|
||||
r = sd_netlink_message_get_errno(m);
|
||||
if (r < 0)
|
||||
log_link_warning_errno(link, r, "Could not set address genmode for interface: %m");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int link_configure_addrgen_mode(Link *link) {
|
||||
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
|
||||
uint8_t ipv6ll_mode;
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
assert(link->network);
|
||||
assert(link->manager);
|
||||
assert(link->manager->rtnl);
|
||||
|
||||
log_link_debug(link, "Setting address genmode for link");
|
||||
|
||||
r = sd_rtnl_message_new_link(link->manager->rtnl, &req, RTM_SETLINK, link->ifindex);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Could not allocate RTM_SETLINK message: %m");
|
||||
|
||||
r = sd_netlink_message_open_container(req, IFLA_AF_SPEC);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Could not open IFLA_AF_SPEC container: %m");
|
||||
|
||||
r = sd_netlink_message_open_container(req, AF_INET6);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Could not open AF_INET6 container: %m");
|
||||
|
||||
if (!link_ipv6ll_enabled(link))
|
||||
ipv6ll_mode = IN6_ADDR_GEN_MODE_NONE;
|
||||
else {
|
||||
const char *p = NULL;
|
||||
_cleanup_free_ char *stable_secret = NULL;
|
||||
|
||||
p = strjoina("/proc/sys/net/ipv6/conf/", link->ifname, "/stable_secret");
|
||||
|
||||
/* The file may not exist. And event if it exists, when stable_secret is unset,
|
||||
* then reading the file fails and EIO is returned. */
|
||||
r = read_one_line_file(p, &stable_secret);
|
||||
if (r < 0)
|
||||
ipv6ll_mode = IN6_ADDR_GEN_MODE_EUI64;
|
||||
else
|
||||
ipv6ll_mode = IN6_ADDR_GEN_MODE_STABLE_PRIVACY;
|
||||
}
|
||||
|
||||
r = sd_netlink_message_append_u8(req, IFLA_INET6_ADDR_GEN_MODE, ipv6ll_mode);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Could not append IFLA_INET6_ADDR_GEN_MODE: %m");
|
||||
|
||||
r = sd_netlink_message_close_container(req);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Could not close AF_INET6 container: %m");
|
||||
|
||||
r = sd_netlink_message_close_container(req);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Could not close IFLA_AF_SPEC container: %m");
|
||||
|
||||
r = netlink_call_async(link->manager->rtnl, NULL, req, link_address_genmode_handler,
|
||||
link_netlink_destroy_callback, link);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
|
||||
|
||||
link_ref(link);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int link_up_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
|
||||
int r;
|
||||
|
||||
@ -1781,7 +1859,6 @@ static int link_up_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link)
|
||||
|
||||
static int link_up(Link *link) {
|
||||
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
|
||||
uint8_t ipv6ll_mode;
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
@ -1812,34 +1889,16 @@ static int link_up(Link *link) {
|
||||
return log_link_error_errno(link, r, "Could not set MAC address: %m");
|
||||
}
|
||||
|
||||
r = sd_netlink_message_open_container(req, IFLA_AF_SPEC);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Could not open IFLA_AF_SPEC container: %m");
|
||||
|
||||
if (link_ipv6_enabled(link)) {
|
||||
r = sd_netlink_message_open_container(req, IFLA_AF_SPEC);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Could not open IFLA_AF_SPEC container: %m");
|
||||
|
||||
/* if the kernel lacks ipv6 support setting IFF_UP fails if any ipv6 options are passed */
|
||||
r = sd_netlink_message_open_container(req, AF_INET6);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Could not open AF_INET6 container: %m");
|
||||
|
||||
if (!link_ipv6ll_enabled(link))
|
||||
ipv6ll_mode = IN6_ADDR_GEN_MODE_NONE;
|
||||
else {
|
||||
const char *p = NULL;
|
||||
_cleanup_free_ char *stable_secret = NULL;
|
||||
|
||||
p = strjoina("/proc/sys/net/ipv6/conf/", link->ifname, "/stable_secret");
|
||||
r = read_one_line_file(p, &stable_secret);
|
||||
|
||||
if (r < 0)
|
||||
ipv6ll_mode = IN6_ADDR_GEN_MODE_EUI64;
|
||||
else
|
||||
ipv6ll_mode = IN6_ADDR_GEN_MODE_STABLE_PRIVACY;
|
||||
}
|
||||
r = sd_netlink_message_append_u8(req, IFLA_INET6_ADDR_GEN_MODE, ipv6ll_mode);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Could not append IFLA_INET6_ADDR_GEN_MODE: %m");
|
||||
|
||||
if (!in_addr_is_null(AF_INET6, &link->network->ipv6_token)) {
|
||||
r = sd_netlink_message_append_in6_addr(req, IFLA_INET6_TOKEN, &link->network->ipv6_token.in6);
|
||||
if (r < 0)
|
||||
@ -1849,11 +1908,11 @@ static int link_up(Link *link) {
|
||||
r = sd_netlink_message_close_container(req);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Could not close AF_INET6 container: %m");
|
||||
}
|
||||
|
||||
r = sd_netlink_message_close_container(req);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Could not close IFLA_AF_SPEC container: %m");
|
||||
r = sd_netlink_message_close_container(req);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Could not close IFLA_AF_SPEC container: %m");
|
||||
}
|
||||
|
||||
r = netlink_call_async(link->manager->rtnl, NULL, req, link_up_handler,
|
||||
link_netlink_destroy_callback, link);
|
||||
@ -2942,6 +3001,12 @@ static int link_configure(Link *link) {
|
||||
return r;
|
||||
}
|
||||
|
||||
if (socket_ipv6_is_supported()) {
|
||||
r = link_configure_addrgen_mode(link);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
return link_configure_after_setting_mtu(link);
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,5 @@
|
||||
[Match]
|
||||
Name=dummy98
|
||||
|
||||
[Network]
|
||||
LinkLocalAddressing=no
|
@ -0,0 +1,5 @@
|
||||
[Match]
|
||||
Name=test1
|
||||
|
||||
[Network]
|
||||
LinkLocalAddressing=yes
|
@ -565,6 +565,8 @@ class NetworkdNetWorkTests(unittest.TestCase, Utilities):
|
||||
'25-fibrule-port-range.network',
|
||||
'25-ipv6-address-label-section.network',
|
||||
'25-neighbor-section.network',
|
||||
'25-link-local-addressing-no.network',
|
||||
'25-link-local-addressing-yes.network',
|
||||
'25-link-section-unmanaged.network',
|
||||
'25-route-gateway.network',
|
||||
'25-route-gateway-on-link.network',
|
||||
@ -861,6 +863,66 @@ class NetworkdNetWorkTests(unittest.TestCase, Utilities):
|
||||
self.assertRegex(output, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT')
|
||||
self.assertRegex(output, '2004:da8:1::1.*00:00:5e:00:02:66.*PERMANENT')
|
||||
|
||||
def test_link_local_addressing(self):
|
||||
self.copy_unit_to_networkd_unit_path('25-link-local-addressing-yes.network', '11-dummy.netdev',
|
||||
'25-link-local-addressing-no.network', '12-dummy.netdev')
|
||||
self.start_networkd()
|
||||
|
||||
self.assertTrue(self.link_exits('test1'))
|
||||
self.assertTrue(self.link_exits('dummy98'))
|
||||
|
||||
time.sleep(10)
|
||||
|
||||
output = subprocess.check_output(['ip', 'address', 'show', 'dev', 'test1']).rstrip().decode('utf-8')
|
||||
print(output)
|
||||
self.assertRegex(output, 'inet .* scope link')
|
||||
self.assertRegex(output, 'inet6 .* scope link')
|
||||
|
||||
output = subprocess.check_output(['ip', 'address', 'show', 'dev', 'dummy98']).rstrip().decode('utf-8')
|
||||
print(output)
|
||||
self.assertNotRegex(output, 'inet6* .* scope link')
|
||||
|
||||
output = subprocess.check_output(['networkctl', 'status', 'test1']).rstrip().decode('utf-8')
|
||||
print(output)
|
||||
self.assertRegex(output, 'State: degraded \(configured\)')
|
||||
|
||||
output = subprocess.check_output(['networkctl', 'status', 'dummy98']).rstrip().decode('utf-8')
|
||||
print(output)
|
||||
self.assertRegex(output, 'State: carrier \(configured\)')
|
||||
|
||||
'''
|
||||
Documentation/networking/ip-sysctl.txt
|
||||
|
||||
addr_gen_mode - INTEGER
|
||||
Defines how link-local and autoconf addresses are generated.
|
||||
|
||||
0: generate address based on EUI64 (default)
|
||||
1: do no generate a link-local address, use EUI64 for addresses generated
|
||||
from autoconf
|
||||
2: generate stable privacy addresses, using the secret from
|
||||
stable_secret (RFC7217)
|
||||
3: generate stable privacy addresses, using a random secret if unset
|
||||
'''
|
||||
|
||||
test1_addr_gen_mode = ''
|
||||
if os.path.exists(os.path.join(os.path.join(network_sysctl_ipv6_path, 'test1'), 'stable_secret')):
|
||||
with open(os.path.join(os.path.join(network_sysctl_ipv6_path, 'test1'), 'stable_secret')) as f:
|
||||
try:
|
||||
f.readline()
|
||||
except IOError:
|
||||
# if stable_secret is unset, then EIO is returned
|
||||
test1_addr_gen_mode = '0'
|
||||
else:
|
||||
test1_addr_gen_mode = '2'
|
||||
else:
|
||||
test1_addr_gen_mode = '0'
|
||||
|
||||
if os.path.exists(os.path.join(os.path.join(network_sysctl_ipv6_path, 'test1'), 'addr_gen_mode')):
|
||||
self.assertEqual(self.read_ipv6_sysctl_attr('test1', 'addr_gen_mode'), '0')
|
||||
|
||||
if os.path.exists(os.path.join(os.path.join(network_sysctl_ipv6_path, 'dummy98'), 'addr_gen_mode')):
|
||||
self.assertEqual(self.read_ipv6_sysctl_attr('dummy98', 'addr_gen_mode'), '1')
|
||||
|
||||
def test_sysctl(self):
|
||||
self.copy_unit_to_networkd_unit_path('25-sysctl.network', '12-dummy.netdev')
|
||||
self.start_networkd()
|
||||
|
Loading…
Reference in New Issue
Block a user