1
0
mirror of https://github.com/systemd/systemd.git synced 2024-12-23 21:35:11 +03:00

Merge pull request #29495 from yuwata/network-manager-state-file

network: fixlets for manager state file
This commit is contained in:
Luca Boccassi 2023-10-08 22:46:44 +01:00 committed by GitHub
commit 00dd4e78f6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 324 additions and 140 deletions

View File

@ -341,7 +341,17 @@ static int dhcp6_lease_ip_acquired(sd_dhcp6_client *client, Link *link) {
}
static int dhcp6_lease_information_acquired(sd_dhcp6_client *client, Link *link) {
return 0;
sd_dhcp6_lease *lease;
int r;
assert(client);
assert(link);
r = sd_dhcp6_client_get_lease(client, &lease);
if (r < 0)
return log_link_error_errno(link, r, "Failed to get DHCPv6 lease: %m");
return unref_and_replace_full(link->dhcp6_lease, lease, sd_dhcp6_lease_ref, sd_dhcp6_lease_unref);
}
static int dhcp6_lease_lost(Link *link) {
@ -366,7 +376,7 @@ static int dhcp6_lease_lost(Link *link) {
static void dhcp6_handler(sd_dhcp6_client *client, int event, void *userdata) {
Link *link = ASSERT_PTR(userdata);
int r;
int r = 0;
assert(link->network);
@ -378,31 +388,24 @@ static void dhcp6_handler(sd_dhcp6_client *client, int event, void *userdata) {
case SD_DHCP6_CLIENT_EVENT_RESEND_EXPIRE:
case SD_DHCP6_CLIENT_EVENT_RETRANS_MAX:
r = dhcp6_lease_lost(link);
if (r < 0)
link_enter_failed(link);
break;
case SD_DHCP6_CLIENT_EVENT_IP_ACQUIRE:
r = dhcp6_lease_ip_acquired(client, link);
if (r < 0) {
link_enter_failed(link);
return;
}
break;
_fallthrough_;
case SD_DHCP6_CLIENT_EVENT_INFORMATION_REQUEST:
r = dhcp6_lease_information_acquired(client, link);
if (r < 0)
link_enter_failed(link);
break;
default:
if (event < 0)
log_link_warning_errno(link, event, "DHCPv6 error: %m");
log_link_warning_errno(link, event, "DHCPv6 error, ignoring: %m");
else
log_link_warning(link, "DHCPv6 unknown event: %d", event);
return;
}
if (r < 0)
link_enter_failed(link);
}
int dhcp6_start_on_ra(Link *link, bool information_request) {

View File

@ -21,64 +21,28 @@
#include "strv.h"
#include "tmpfile-util.h"
static int ordered_set_put_dns_server(OrderedSet **s, int ifindex, struct in_addr_full *dns) {
const char *p;
int r;
assert(s);
assert(dns);
if (dns->ifindex != 0 && dns->ifindex != ifindex)
return 0;
p = in_addr_full_to_string(dns);
if (!p)
return 0;
r = ordered_set_put_strdup(s, p);
if (r == -EEXIST)
return 0;
return r;
}
static int ordered_set_put_dns_servers(OrderedSet **s, int ifindex, struct in_addr_full **dns, unsigned n) {
int r, c = 0;
int r;
assert(s);
assert(dns || n == 0);
for (unsigned i = 0; i < n; i++) {
r = ordered_set_put_dns_server(s, ifindex, dns[i]);
FOREACH_ARRAY(a, dns, n) {
const char *p;
if ((*a)->ifindex != 0 && (*a)->ifindex != ifindex)
return 0;
p = in_addr_full_to_string(*a);
if (!p)
return 0;
r = ordered_set_put_strdup(s, p);
if (r < 0)
return r;
c += r;
}
return c;
}
static int ordered_set_put_in4_addr(OrderedSet **s, const struct in_addr *address) {
_cleanup_free_ char *p = NULL;
int r;
assert(s);
assert(address);
r = in_addr_to_string(AF_INET, (const union in_addr_union*) address, &p);
if (r < 0)
return r;
r = ordered_set_ensure_allocated(s, &string_hash_ops_free);
if (r < 0)
return r;
r = ordered_set_consume(*s, TAKE_PTR(p));
if (r == -EEXIST)
return 0;
return r;
return 0;
}
static int ordered_set_put_in4_addrv(
@ -87,22 +51,220 @@ static int ordered_set_put_in4_addrv(
size_t n,
bool (*predicate)(const struct in_addr *addr)) {
int r, c = 0;
int r;
assert(s);
assert(n == 0 || addresses);
for (size_t i = 0; i < n; i++) {
if (predicate && !predicate(&addresses[i]))
FOREACH_ARRAY(a, addresses, n) {
if (predicate && !predicate(a))
continue;
r = ordered_set_put_in4_addr(s, addresses+i);
r = ordered_set_put_strdup(s, IN4_ADDR_TO_STRING(a));
if (r < 0)
return r;
c += r;
}
return c;
return 0;
}
static int ordered_set_put_in6_addrv(
OrderedSet **s,
const struct in6_addr *addresses,
size_t n) {
int r;
assert(s);
assert(n == 0 || addresses);
FOREACH_ARRAY(a, addresses, n) {
r = ordered_set_put_strdup(s, IN6_ADDR_TO_STRING(a));
if (r < 0)
return r;
}
return 0;
}
static int link_put_dns(Link *link, OrderedSet **s) {
int r;
assert(link);
assert(link->network);
assert(s);
if (link->n_dns != UINT_MAX)
return ordered_set_put_dns_servers(s, link->ifindex, link->dns, link->n_dns);
r = ordered_set_put_dns_servers(s, link->ifindex, link->network->dns, link->network->n_dns);
if (r < 0)
return r;
if (link->dhcp_lease && link->network->dhcp_use_dns) {
const struct in_addr *addresses;
r = sd_dhcp_lease_get_dns(link->dhcp_lease, &addresses);
if (r >= 0) {
r = ordered_set_put_in4_addrv(s, addresses, r, in4_addr_is_non_local);
if (r < 0)
return r;
}
}
if (link->dhcp6_lease && link->network->dhcp6_use_dns) {
const struct in6_addr *addresses;
r = sd_dhcp6_lease_get_dns(link->dhcp6_lease, &addresses);
if (r >= 0) {
r = ordered_set_put_in6_addrv(s, addresses, r);
if (r < 0)
return r;
}
}
if (link->network->ipv6_accept_ra_use_dns) {
NDiscRDNSS *a;
SET_FOREACH(a, link->ndisc_rdnss) {
r = ordered_set_put_in6_addrv(s, &a->router, 1);
if (r < 0)
return r;
}
}
return 0;
}
static int link_put_ntp(Link *link, OrderedSet **s) {
int r;
assert(link);
assert(link->network);
assert(s);
if (link->ntp)
return ordered_set_put_strdupv(s, link->ntp);
r = ordered_set_put_strdupv(s, link->network->ntp);
if (r < 0)
return r;
if (link->dhcp_lease && link->network->dhcp_use_ntp) {
const struct in_addr *addresses;
r = sd_dhcp_lease_get_ntp(link->dhcp_lease, &addresses);
if (r >= 0) {
r = ordered_set_put_in4_addrv(s, addresses, r, in4_addr_is_non_local);
if (r < 0)
return r;
}
}
if (link->dhcp6_lease && link->network->dhcp6_use_ntp) {
const struct in6_addr *addresses;
char **fqdn;
r = sd_dhcp6_lease_get_ntp_addrs(link->dhcp6_lease, &addresses);
if (r >= 0) {
r = ordered_set_put_in6_addrv(s, addresses, r);
if (r < 0)
return r;
}
r = sd_dhcp6_lease_get_ntp_fqdn(link->dhcp6_lease, &fqdn);
if (r >= 0) {
r = ordered_set_put_strdupv(s, fqdn);
if (r < 0)
return r;
}
}
return 0;
}
static int link_put_sip(Link *link, OrderedSet **s) {
int r;
assert(link);
assert(link->network);
assert(s);
if (link->dhcp_lease && link->network->dhcp_use_ntp) {
const struct in_addr *addresses;
r = sd_dhcp_lease_get_sip(link->dhcp_lease, &addresses);
if (r >= 0) {
r = ordered_set_put_in4_addrv(s, addresses, r, in4_addr_is_non_local);
if (r < 0)
return r;
}
}
return 0;
}
static int link_put_domains(Link *link, bool is_route, OrderedSet **s) {
OrderedSet *link_domains, *network_domains;
DHCPUseDomains use_domains;
int r;
assert(link);
assert(link->network);
assert(s);
link_domains = is_route ? link->route_domains : link->search_domains;
network_domains = is_route ? link->network->route_domains : link->network->search_domains;
use_domains = is_route ? DHCP_USE_DOMAINS_ROUTE : DHCP_USE_DOMAINS_YES;
if (link_domains)
return ordered_set_put_string_set(s, link_domains);
r = ordered_set_put_string_set(s, network_domains);
if (r < 0)
return r;
if (link->dhcp_lease && link->network->dhcp_use_domains == use_domains) {
const char *domainname;
char **domains;
r = sd_dhcp_lease_get_domainname(link->dhcp_lease, &domainname);
if (r >= 0) {
r = ordered_set_put_strdup(s, domainname);
if (r < 0)
return r;
}
r = sd_dhcp_lease_get_search_domains(link->dhcp_lease, &domains);
if (r >= 0) {
r = ordered_set_put_strdupv(s, domains);
if (r < 0)
return r;
}
}
if (link->dhcp6_lease && link->network->dhcp6_use_domains == use_domains) {
char **domains;
r = sd_dhcp6_lease_get_domains(link->dhcp6_lease, &domains);
if (r >= 0) {
r = ordered_set_put_strdupv(s, domains);
if (r < 0)
return r;
}
}
if (link->network->ipv6_accept_ra_use_domains == use_domains) {
NDiscDNSSL *a;
SET_FOREACH(a, link->ndisc_dnssl) {
r = ordered_set_put_strdup(s, NDISC_DNSSL_DOMAIN(a));
if (r < 0)
return r;
}
}
return 0;
}
int manager_save(Manager *m) {
@ -126,8 +288,6 @@ int manager_save(Manager *m) {
return 0; /* Do not update state file when running in test mode. */
HASHMAP_FOREACH(link, m->links_by_index) {
const struct in_addr *addresses;
if (link->flags & IFF_LOOPBACK)
continue;
@ -147,82 +307,25 @@ int manager_save(Manager *m) {
links_online++;
}
/* First add the static configured entries */
if (link->n_dns != UINT_MAX)
r = ordered_set_put_dns_servers(&dns, link->ifindex, link->dns, link->n_dns);
else
r = ordered_set_put_dns_servers(&dns, link->ifindex, link->network->dns, link->network->n_dns);
r = link_put_dns(link, &dns);
if (r < 0)
return r;
r = ordered_set_put_strdupv(&ntp, link->ntp ?: link->network->ntp);
r = link_put_ntp(link, &ntp);
if (r < 0)
return r;
r = ordered_set_put_string_set(&search_domains, link->search_domains ?: link->network->search_domains);
r = link_put_sip(link, &sip);
if (r < 0)
return r;
r = ordered_set_put_string_set(&route_domains, link->route_domains ?: link->network->route_domains);
r = link_put_domains(link, /* is_route = */ false, &search_domains);
if (r < 0)
return r;
if (!link->dhcp_lease)
continue;
/* Secondly, add the entries acquired via DHCP */
if (link->network->dhcp_use_dns) {
r = sd_dhcp_lease_get_dns(link->dhcp_lease, &addresses);
if (r > 0) {
r = ordered_set_put_in4_addrv(&dns, addresses, r, in4_addr_is_non_local);
if (r < 0)
return r;
} else if (r < 0 && r != -ENODATA)
return r;
}
if (link->network->dhcp_use_ntp) {
r = sd_dhcp_lease_get_ntp(link->dhcp_lease, &addresses);
if (r > 0) {
r = ordered_set_put_in4_addrv(&ntp, addresses, r, in4_addr_is_non_local);
if (r < 0)
return r;
} else if (r < 0 && r != -ENODATA)
return r;
}
if (link->network->dhcp_use_sip) {
r = sd_dhcp_lease_get_sip(link->dhcp_lease, &addresses);
if (r > 0) {
r = ordered_set_put_in4_addrv(&sip, addresses, r, in4_addr_is_non_local);
if (r < 0)
return r;
} else if (r < 0 && r != -ENODATA)
return r;
}
if (link->network->dhcp_use_domains != DHCP_USE_DOMAINS_NO) {
OrderedSet **target_domains;
const char *domainname;
char **domains = NULL;
target_domains = link->network->dhcp_use_domains == DHCP_USE_DOMAINS_YES ? &search_domains : &route_domains;
r = sd_dhcp_lease_get_domainname(link->dhcp_lease, &domainname);
if (r >= 0) {
r = ordered_set_put_strdup(target_domains, domainname);
if (r < 0)
return r;
} else if (r != -ENODATA)
return r;
r = sd_dhcp_lease_get_search_domains(link->dhcp_lease, &domains);
if (r >= 0) {
r = ordered_set_put_strdupv(target_domains, domains);
if (r < 0)
return r;
} else if (r != -ENODATA)
return r;
}
r = link_put_domains(link, /* is_route = */ true, &route_domains);
if (r < 0)
return r;
}
if (carrier_state >= LINK_CARRIER_STATE_ENSLAVED)

View File

@ -9,3 +9,7 @@ IPv6Token=::1a:2b:3c:4d
[Route]
Gateway=_ipv6ra
Destination=2001:1234:5:9fff:ff:ff:ff:ff/128
[IPv6AcceptRA]
# To check DNS and NTP servers are really obtained by DHCPv6
UseDNS=no

View File

@ -534,6 +534,10 @@ def read_link_attr(*args):
with open(os.path.join('/sys/class/net', *args), encoding='utf-8') as f:
return f.readline().strip()
def read_manager_state_file():
with open('/run/systemd/netif/state', encoding='utf-8') as f:
return f.read()
def read_link_state_file(link):
ifindex = read_link_attr(link, 'ifindex')
path = os.path.join('/run/systemd/netif/links', ifindex)
@ -567,7 +571,12 @@ def stop_by_pid_file(pid_file):
print(f"Unexpected exception when waiting for {pid} to die: {e.errno}")
rm_f(pid_file)
def start_dnsmasq(*additional_options, interface='veth-peer', lease_time='2m', ipv4_range='192.168.5.10,192.168.5.200', ipv4_router='192.168.5.1', ipv6_range='2600::10,2600::20'):
def start_dnsmasq(*additional_options, interface='veth-peer', ra_mode=None, ipv4_range='192.168.5.10,192.168.5.200', ipv4_router='192.168.5.1', ipv6_range='2600::10,2600::20'):
if ra_mode:
ra_mode = f',{ra_mode}'
else:
ra_mode = ''
command = (
'dnsmasq',
f'--log-facility={dnsmasq_log_file}',
@ -579,8 +588,8 @@ def start_dnsmasq(*additional_options, interface='veth-peer', lease_time='2m', i
f'--interface={interface}',
f'--dhcp-leasefile={dnsmasq_lease_file}',
'--enable-ra',
f'--dhcp-range={ipv6_range},{lease_time}',
f'--dhcp-range={ipv4_range},{lease_time}',
f'--dhcp-range={ipv6_range}{ra_mode},2m',
f'--dhcp-range={ipv4_range},2m',
'--dhcp-option=option:mtu,1492',
f'--dhcp-option=option:router,{ipv4_router}',
'--port=0',
@ -5099,7 +5108,41 @@ class NetworkdDHCPClientTests(unittest.TestCase, Utilities):
start_networkd()
self.wait_online(['veth-peer:carrier'])
start_dnsmasq()
# information request mode
start_dnsmasq('--dhcp-option=option6:dns-server,[2600::ee]',
'--dhcp-option=option6:ntp-server,[2600::ff]',
ra_mode='ra-stateless')
self.wait_online(['veth99:routable', 'veth-peer:routable'])
# Check link state file
print('## link state file')
output = read_link_state_file('veth99')
print(output)
self.assertIn('DNS=2600::ee', output)
self.assertIn('NTP=2600::ff', output)
# Check manager state file
print('## manager state file')
output = read_manager_state_file()
print(output)
self.assertRegex(output, 'DNS=.*2600::ee')
self.assertRegex(output, 'NTP=.*2600::ff')
print('## dnsmasq log')
output = read_dnsmasq_log_file()
print(output)
self.assertIn('DHCPINFORMATION-REQUEST(veth-peer)', output)
self.assertNotIn('DHCPSOLICIT(veth-peer)', output)
self.assertNotIn('DHCPADVERTISE(veth-peer)', output)
self.assertNotIn('DHCPREQUEST(veth-peer)', output)
self.assertNotIn('DHCPREPLY(veth-peer)', output)
# solicit mode
stop_dnsmasq()
start_dnsmasq('--dhcp-option=option6:dns-server,[2600::ee]',
'--dhcp-option=option6:ntp-server,[2600::ff]')
networkctl_reconfigure('veth99')
self.wait_online(['veth99:routable', 'veth-peer:routable'])
# checking address
@ -5118,9 +5161,24 @@ class NetworkdDHCPClientTests(unittest.TestCase, Utilities):
print(output)
self.assertRegex(output, 'token :: dev veth99')
# Check link state file
print('## link state file')
output = read_link_state_file('veth99')
print(output)
self.assertIn('DNS=2600::ee', output)
self.assertIn('NTP=2600::ff', output)
# Check manager state file
print('## manager state file')
output = read_manager_state_file()
print(output)
self.assertRegex(output, 'DNS=.*2600::ee')
self.assertRegex(output, 'NTP=.*2600::ff')
print('## dnsmasq log')
output = read_dnsmasq_log_file()
print(output)
self.assertNotIn('DHCPINFORMATION-REQUEST(veth-peer)', output)
self.assertIn('DHCPSOLICIT(veth-peer)', output)
self.assertNotIn('DHCPADVERTISE(veth-peer)', output)
self.assertNotIn('DHCPREQUEST(veth-peer)', output)
@ -5131,7 +5189,8 @@ class NetworkdDHCPClientTests(unittest.TestCase, Utilities):
f.write('\n[DHCPv6]\nRapidCommit=no\n')
stop_dnsmasq()
start_dnsmasq()
start_dnsmasq('--dhcp-option=option6:dns-server,[2600::ee]',
'--dhcp-option=option6:ntp-server,[2600::ff]')
networkctl_reload()
self.wait_online(['veth99:routable', 'veth-peer:routable'])
@ -5147,9 +5206,24 @@ class NetworkdDHCPClientTests(unittest.TestCase, Utilities):
print(output)
self.assertRegex(output, 'via fe80::1034:56ff:fe78:9abd')
# Check link state file
print('## link state file')
output = read_link_state_file('veth99')
print(output)
self.assertIn('DNS=2600::ee', output)
self.assertIn('NTP=2600::ff', output)
# Check manager state file
print('## manager state file')
output = read_manager_state_file()
print(output)
self.assertRegex(output, 'DNS=.*2600::ee')
self.assertRegex(output, 'NTP=.*2600::ff')
print('## dnsmasq log')
output = read_dnsmasq_log_file()
print(output)
self.assertNotIn('DHCPINFORMATION-REQUEST(veth-peer)', output)
self.assertIn('DHCPSOLICIT(veth-peer)', output)
self.assertIn('DHCPADVERTISE(veth-peer)', output)
self.assertIn('DHCPREQUEST(veth-peer)', output)