summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYu Watanabe <watanabe.yu+github@gmail.com>2021-12-19 08:52:08 +0900
committerGitHub <noreply@github.com>2021-12-19 08:52:08 +0900
commitecb0be874d8ad32e520efc52e26756b23154e43d (patch)
treecd2d5b9833b1af88a0cd8464fd11835d7574c178
parent5cfe61f2de3d388dd10a9d1e0cf07a844a429209 (diff)
parent6a936c9c9ab77a884a579636d6349770f21b2adc (diff)
downloadsystemd-ecb0be874d8ad32e520efc52e26756b23154e43d.tar.gz
Merge pull request #21814 from yuwata/network-dhcp-pd-fixes
network: several fixes for DHCP prefix delegation
-rw-r--r--src/libsystemd-network/sd-dhcp-client.c2
-rw-r--r--src/libsystemd-network/sd-radv.c50
-rw-r--r--src/network/netdev/tunnel.c4
-rw-r--r--src/network/networkd-dhcp-prefix-delegation.c2
-rw-r--r--src/network/networkd-route.c14
-rw-r--r--test/test-network/conf/isc-dhcpd-6rd.conf22
-rwxr-xr-xtest/test-network/systemd-networkd-tests.py128
7 files changed, 114 insertions, 108 deletions
diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c
index 16574d28c7..c33be947b7 100644
--- a/src/libsystemd-network/sd-dhcp-client.c
+++ b/src/libsystemd-network/sd-dhcp-client.c
@@ -1994,6 +1994,7 @@ static int client_receive_message_udp(
return 0;
}
+ log_dhcp_client(client, "Received message from UDP socket, processing.");
(void) client_handle_message(client, message, len);
return 0;
}
@@ -2060,6 +2061,7 @@ static int client_receive_message_raw(
len -= DHCP_IP_UDP_SIZE;
+ log_dhcp_client(client, "Received message from RAW socket, processing.");
(void) client_handle_message(client, &packet->dhcp, len);
return 0;
}
diff --git a/src/libsystemd-network/sd-radv.c b/src/libsystemd-network/sd-radv.c
index f8ffb6358f..a305171902 100644
--- a/src/libsystemd-network/sd-radv.c
+++ b/src/libsystemd-network/sd-radv.c
@@ -617,7 +617,8 @@ int sd_radv_add_prefix(sd_radv *ra, sd_radv_prefix *p) {
strna(addr_p),
FORMAT_TIMESPAN(p->lifetime_preferred_usec, USEC_PER_SEC),
FORMAT_TIMESPAN(p->lifetime_valid_usec, USEC_PER_SEC));
- return 0;
+
+ goto announce;
}
_cleanup_free_ char *addr_cur = NULL;
@@ -631,19 +632,21 @@ int sd_radv_add_prefix(sd_radv *ra, sd_radv_prefix *p) {
LIST_APPEND(prefix, ra->prefixes, p);
ra->n_prefixes++;
- if (ra->state == RADV_STATE_IDLE) {
- log_radv(ra, "Added prefix %s", strna(addr_p));
+ log_radv(ra, "Added prefix %s", strna(addr_p));
+
+ if (ra->state == RADV_STATE_IDLE)
+ return 0;
+
+announce:
+ if (ra->ra_sent == 0)
return 0;
- }
/* If RAs have already been sent, send an RA immediately to announce the newly-added prefix */
- if (ra->ra_sent > 0) {
- r = radv_send(ra, NULL, ra->lifetime_usec);
- if (r < 0)
- log_radv_errno(ra, r, "Unable to send Router Advertisement for added prefix: %m");
- else
- log_radv(ra, "Sent Router Advertisement for added prefix");
- }
+ r = radv_send(ra, NULL, ra->lifetime_usec);
+ if (r < 0)
+ log_radv_errno(ra, r, "Unable to send Router Advertisement for added prefix: %m");
+ else
+ log_radv(ra, "Sent Router Advertisement for added/updated prefix");
return 0;
}
@@ -709,7 +712,8 @@ int sd_radv_add_route_prefix(sd_radv *ra, sd_radv_route_prefix *p) {
log_radv(ra, "Updated/replaced IPv6 route prefix %s (lifetime: %s)",
strna(addr_p),
FORMAT_TIMESPAN(p->lifetime_usec, USEC_PER_SEC));
- return 0;
+
+ goto announce;
}
_cleanup_free_ char *addr_cur = NULL;
@@ -723,19 +727,21 @@ int sd_radv_add_route_prefix(sd_radv *ra, sd_radv_route_prefix *p) {
LIST_APPEND(prefix, ra->route_prefixes, p);
ra->n_route_prefixes++;
- if (ra->state == RADV_STATE_IDLE) {
- log_radv(ra, "Added route prefix %s", strna(addr_p));
+ log_radv(ra, "Added route prefix %s", strna(addr_p));
+
+ if (ra->state == RADV_STATE_IDLE)
+ return 0;
+
+announce:
+ if (ra->ra_sent == 0)
return 0;
- }
/* If RAs have already been sent, send an RA immediately to announce the newly-added route prefix */
- if (ra->ra_sent > 0) {
- r = radv_send(ra, NULL, ra->lifetime_usec);
- if (r < 0)
- log_radv_errno(ra, r, "Unable to send Router Advertisement for added route prefix: %m");
- else
- log_radv(ra, "Sent Router Advertisement for added route prefix");
- }
+ r = radv_send(ra, NULL, ra->lifetime_usec);
+ if (r < 0)
+ log_radv_errno(ra, r, "Unable to send Router Advertisement for added route prefix: %m");
+ else
+ log_radv(ra, "Sent Router Advertisement for added route prefix");
return 0;
}
diff --git a/src/network/netdev/tunnel.c b/src/network/netdev/tunnel.c
index 59da4d4376..97e534fe99 100644
--- a/src/network/netdev/tunnel.c
+++ b/src/network/netdev/tunnel.c
@@ -124,10 +124,6 @@ int dhcp4_pd_create_6rd_tunnel(Link *link, link_netlink_message_handler_t callba
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");
diff --git a/src/network/networkd-dhcp-prefix-delegation.c b/src/network/networkd-dhcp-prefix-delegation.c
index 5f2555fe6e..949c74bd58 100644
--- a/src/network/networkd-dhcp-prefix-delegation.c
+++ b/src/network/networkd-dhcp-prefix-delegation.c
@@ -667,7 +667,7 @@ void dhcp_pd_prefix_lost(Link *uplink) {
}
SET_FOREACH(route, uplink->manager->routes) {
- if (IN_SET(route->source, NETWORK_CONFIG_SOURCE_DHCP4, NETWORK_CONFIG_SOURCE_DHCP6))
+ if (!IN_SET(route->source, NETWORK_CONFIG_SOURCE_DHCP4, NETWORK_CONFIG_SOURCE_DHCP6))
continue;
if (route->family != AF_INET6)
continue;
diff --git a/src/network/networkd-route.c b/src/network/networkd-route.c
index 156476066a..ee7a535075 100644
--- a/src/network/networkd-route.c
+++ b/src/network/networkd-route.c
@@ -792,6 +792,10 @@ static void manager_mark_routes(Manager *manager, bool foreign, const Link *exce
if (foreign && route->source != NETWORK_CONFIG_SOURCE_FOREIGN)
continue;
+ /* Do not touch dynamic routes. They will removed by dhcp_pd_prefix_lost() */
+ if (IN_SET(route->source, NETWORK_CONFIG_SOURCE_DHCP4, NETWORK_CONFIG_SOURCE_DHCP6))
+ continue;
+
/* Ignore routes not assigned yet or already removed. */
if (!route_exists(route))
continue;
@@ -1342,6 +1346,16 @@ int link_request_route(
existing->lifetime_usec = route->lifetime_usec;
if (consume_object)
route_free(route);
+
+ if (existing->expire) {
+ /* When re-configuring an existing route, kernel does not send RTM_NEWROUTE
+ * message, so we need to update the timer here. */
+ r = route_setup_timer(existing, NULL);
+ if (r < 0)
+ log_link_warning_errno(link, r, "Failed to update expiration timer for route, ignoring: %m");
+ if (r > 0)
+ log_route_debug(existing, "Updated expiration timer for", link, link->manager);
+ }
}
log_route_debug(existing, "Requesting", link, link->manager);
diff --git a/test/test-network/conf/isc-dhcpd-6rd.conf b/test/test-network/conf/isc-dhcpd-6rd.conf
deleted file mode 100644
index 0b32f4b696..0000000000
--- a/test/test-network/conf/isc-dhcpd-6rd.conf
+++ /dev/null
@@ -1,22 +0,0 @@
-default-lease-time 2592000;
-preferred-lifetime 604800;
-
-default-lease-time 600;
-max-lease-time 7200;
-
-option domain-name-servers 10.0.0.2;
-option domain-search "test.example.com","example.com";
-
-# ipv4masklen = 8
-# 6rd prefix = 2001:db8::/32
-# BR address = 10.0.0.1
-option option-6rd code 212 = {
- integer 8, integer 8, ip6-address, array of ip-address
-};
-
-option option-6rd 8 32 2001:db8:: 10.0.0.1;
-
-subnet 10.0.0.0 netmask 255.0.0.0 {
- # Addresses available to clients
- range 10.100.100.100 10.100.100.199;
-}
diff --git a/test/test-network/systemd-networkd-tests.py b/test/test-network/systemd-networkd-tests.py
index a55ac4de7e..cc450aeb96 100755
--- a/test/test-network/systemd-networkd-tests.py
+++ b/test/test-network/systemd-networkd-tests.py
@@ -502,8 +502,8 @@ def remove_networkd_conf_dropin(dropins):
if (os.path.exists(os.path.join(networkd_conf_dropin_path, dropin))):
os.remove(os.path.join(networkd_conf_dropin_path, dropin))
-def start_dnsmasq(additional_options='', ipv4_range='192.168.5.10,192.168.5.200', ipv6_range='2600::10,2600::20', lease_time='1h'):
- dnsmasq_command = f'dnsmasq -8 {dnsmasq_log_file} --log-queries=extra --log-dhcp --pid-file={dnsmasq_pid_file} --conf-file=/dev/null --interface=veth-peer --enable-ra --dhcp-range={ipv6_range},{lease_time} --dhcp-range={ipv4_range},{lease_time} -R --dhcp-leasefile={dnsmasq_lease_file} --dhcp-option=26,1492 --dhcp-option=option:router,192.168.5.1 --port=0 ' + additional_options
+def start_dnsmasq(additional_options='', interface='veth-peer', ipv4_range='192.168.5.10,192.168.5.200', ipv4_router='192.168.5.1', ipv6_range='2600::10,2600::20', lease_time='1h'):
+ dnsmasq_command = f'dnsmasq -8 {dnsmasq_log_file} --log-queries=extra --log-dhcp --pid-file={dnsmasq_pid_file} --conf-file=/dev/null --bind-interfaces --interface={interface} --enable-ra --dhcp-range={ipv6_range},{lease_time} --dhcp-range={ipv4_range},{lease_time} -R --dhcp-leasefile={dnsmasq_lease_file} --dhcp-option=26,1492 --dhcp-option=option:router,{ipv4_router} --port=0 ' + additional_options
check_output(dnsmasq_command)
def stop_by_pid_file(pid_file):
@@ -526,6 +526,11 @@ def stop_by_pid_file(pid_file):
def stop_dnsmasq():
stop_by_pid_file(dnsmasq_pid_file)
+def dump_dnsmasq_log_file():
+ if os.path.exists(dnsmasq_log_file):
+ with open (dnsmasq_log_file) as in_file:
+ print(in_file.read())
+
def search_words_in_dnsmasq_log(words, show_all=False):
if os.path.exists(dnsmasq_log_file):
with open (dnsmasq_log_file) as in_file:
@@ -5028,11 +5033,13 @@ class NetworkdDHCPPDTests(unittest.TestCase, Utilities):
def setUp(self):
stop_isc_dhcpd()
+ stop_dnsmasq()
remove_links(self.links)
stop_networkd(show_logs=False)
def tearDown(self):
stop_isc_dhcpd()
+ stop_dnsmasq()
remove_links(self.links)
remove_unit_from_networkd_path(self.units)
stop_networkd(show_logs=True)
@@ -5231,22 +5238,7 @@ class NetworkdDHCPPDTests(unittest.TestCase, Utilities):
print(output)
self.assertRegex(output, '3ffe:501:ffff:[2-9a-f]03::/64 proto dhcp metric [0-9]* expires')
- def test_dhcp4_6rd(self):
- copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp4-6rd-server.network', 'dhcp4-6rd-upstream.network',
- '25-veth-downstream-veth97.netdev', 'dhcp-pd-downstream-veth97.network', 'dhcp-pd-downstream-veth97-peer.network',
- '25-veth-downstream-veth98.netdev', 'dhcp-pd-downstream-veth98.network', 'dhcp-pd-downstream-veth98-peer.network',
- '11-dummy.netdev', 'dhcp-pd-downstream-test1.network',
- 'dhcp-pd-downstream-dummy97.network',
- '12-dummy.netdev', 'dhcp-pd-downstream-dummy98.network',
- '13-dummy.netdev', 'dhcp-pd-downstream-dummy99.network',
- '80-6rd-tunnel.network')
-
- start_networkd()
- self.wait_online(['veth-peer:routable'])
- start_isc_dhcpd('veth-peer', 'isc-dhcpd-6rd.conf', ip='-4')
- self.wait_online(['veth99:routable', 'test1:routable', 'dummy98:routable', 'dummy99:degraded',
- 'veth97:routable', 'veth97-peer:routable', 'veth98:routable', 'veth98-peer:routable'])
-
+ def verify_dhcp4_6rd(self, tunnel_name):
print('### ip -4 address show dev veth-peer scope global')
output = check_output('ip -4 address show dev veth-peer scope global')
print(output)
@@ -5386,10 +5378,6 @@ class NetworkdDHCPPDTests(unittest.TestCase, Utilities):
print(output)
self.assertRegex(output, '2001:db8:6464:[0-9a-f]+09::/64 proto ra metric [0-9]* expires')
- # Test case for a downstream which appears later
- check_output('ip link add dummy97 type dummy')
- self.wait_online(['dummy97:routable'])
-
print('### ip -6 address show dev dummy97 scope global')
output = check_output('ip -6 address show dev dummy97 scope global')
print(output)
@@ -5403,48 +5391,11 @@ class NetworkdDHCPPDTests(unittest.TestCase, Utilities):
print(output)
self.assertRegex(output, '2001:db8:6464:[0-9a-f]+01::/64 proto kernel metric [0-9]* expires')
- # Test case for reconfigure
- check_output(*networkctl_cmd, 'reconfigure', 'dummy98', 'dummy99', env=env)
- self.wait_online(['dummy98:routable'])
-
- print('### ip -6 address show dev dummy98 scope global')
- output = check_output('ip -6 address show dev dummy98 scope global')
- print(output)
- # address in IA_PD (Token=static)
- self.assertRegex(output, 'inet6 2001:db8:6464:[0-9a-f]+02:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr')
- # address in IA_PD (temporary)
- self.wait_address('dummy98', 'inet6 2001:db8:6464:[0-9a-f]+02:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*/64 (metric 256 |)scope global temporary dynamic', ipv='-6')
-
- print('### ip -6 address show dev dummy99 scope global')
- output = check_output('ip -6 address show dev dummy99 scope global')
- print(output)
- # Assign=no
- self.assertNotRegex(output, 'inet6 2001:db8:6464:[0-9a-f]+03')
-
- print('### ip -6 route show dev dummy98')
- output = check_output('ip -6 route show dev dummy98')
- print(output)
- self.assertRegex(output, '2001:db8:6464:[0-9a-f]+02::/64 proto kernel metric [0-9]* expires')
-
- print('### ip -6 route show dev dummy99')
- output = check_output('ip -6 route show dev dummy99')
- print(output)
- self.assertRegex(output, '2001:db8:6464:[0-9a-f]+03::/64 proto dhcp metric [0-9]* expires')
-
- tunnel_name = None
- for name in os.listdir('/sys/class/net/'):
- if name.startswith('6rd-'):
- tunnel_name = name
- break
-
- self.wait_online(['{}:routable'.format(tunnel_name)])
-
print('### ip -d link show dev {}'.format(tunnel_name))
output = check_output('ip -d link show dev {}'.format(tunnel_name))
print(output)
self.assertIn('link/sit 10.100.100.', output)
self.assertIn('local 10.100.100.', output)
- self.assertIn('dev veth99', output)
self.assertIn('ttl 64', output)
self.assertIn('6rd-prefix 2001:db8::/32', output)
self.assertIn('6rd-relay_prefix 10.0.0.0/8', output)
@@ -5467,6 +5418,65 @@ class NetworkdDHCPPDTests(unittest.TestCase, Utilities):
self.assertIn('default', output)
self.assertIn('via ::10.0.0.1 dev {}'.format(tunnel_name), output)
+ def test_dhcp4_6rd(self):
+ copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp4-6rd-server.network', 'dhcp4-6rd-upstream.network',
+ '25-veth-downstream-veth97.netdev', 'dhcp-pd-downstream-veth97.network', 'dhcp-pd-downstream-veth97-peer.network',
+ '25-veth-downstream-veth98.netdev', 'dhcp-pd-downstream-veth98.network', 'dhcp-pd-downstream-veth98-peer.network',
+ '11-dummy.netdev', 'dhcp-pd-downstream-test1.network',
+ 'dhcp-pd-downstream-dummy97.network',
+ '12-dummy.netdev', 'dhcp-pd-downstream-dummy98.network',
+ '13-dummy.netdev', 'dhcp-pd-downstream-dummy99.network',
+ '80-6rd-tunnel.network')
+
+ start_networkd()
+ self.wait_online(['veth-peer:routable'])
+ '''
+ ipv4masklen: 8
+ 6rd-prefix: 2001:db8::/32
+ br-addresss: 10.0.0.1
+ '''
+ start_dnsmasq(additional_options='--dhcp-option=212,08:20:20:01:0d:b8:00:00:00:00:00:00:00:00:00:00:00:00:0a:00:00:01', ipv4_range='10.100.100.100,10.100.100.200', ipv4_router='10.0.0.1', lease_time='2m')
+ self.wait_online(['veth99:routable', 'test1:routable', 'dummy98:routable', 'dummy99:degraded',
+ 'veth97:routable', 'veth97-peer:routable', 'veth98:routable', 'veth98-peer:routable'])
+
+ # Test case for a downstream which appears later
+ check_output('ip link add dummy97 type dummy')
+ self.wait_online(['dummy97:routable'])
+
+ # Find tunnel name
+ tunnel_name = None
+ for name in os.listdir('/sys/class/net/'):
+ if name.startswith('6rd-'):
+ tunnel_name = name
+ break
+
+ self.wait_online(['{}:routable'.format(tunnel_name)])
+
+ self.verify_dhcp4_6rd(tunnel_name)
+
+ # Test case for reconfigure
+ check_output(*networkctl_cmd, 'reconfigure', 'dummy98', 'dummy99', env=env)
+ self.wait_online(['dummy98:routable', 'dummy99:degraded'])
+
+ self.verify_dhcp4_6rd(tunnel_name)
+
+ # Test for renewing/rebinding lease
+ print('wait for 120 sec')
+ time.sleep(30)
+ print('wait for 90 sec')
+ time.sleep(30)
+ print('wait for 60 sec')
+ time.sleep(30)
+ print('wait for 30 sec')
+ time.sleep(30)
+
+ dump_dnsmasq_log_file()
+
+ self.wait_online(['veth99:routable', 'test1:routable', 'dummy97:routable', 'dummy98:routable', 'dummy99:degraded',
+ 'veth97:routable', 'veth97-peer:routable', 'veth98:routable', 'veth98-peer:routable'])
+
+ self.verify_dhcp4_6rd(tunnel_name)
+
class NetworkdIPv6PrefixTests(unittest.TestCase, Utilities):
links = [
'dummy98',