diff options
author | Yu Watanabe <watanabe.yu+github@gmail.com> | 2021-12-19 08:52:08 +0900 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-12-19 08:52:08 +0900 |
commit | ecb0be874d8ad32e520efc52e26756b23154e43d (patch) | |
tree | cd2d5b9833b1af88a0cd8464fd11835d7574c178 | |
parent | 5cfe61f2de3d388dd10a9d1e0cf07a844a429209 (diff) | |
parent | 6a936c9c9ab77a884a579636d6349770f21b2adc (diff) | |
download | systemd-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.c | 2 | ||||
-rw-r--r-- | src/libsystemd-network/sd-radv.c | 50 | ||||
-rw-r--r-- | src/network/netdev/tunnel.c | 4 | ||||
-rw-r--r-- | src/network/networkd-dhcp-prefix-delegation.c | 2 | ||||
-rw-r--r-- | src/network/networkd-route.c | 14 | ||||
-rw-r--r-- | test/test-network/conf/isc-dhcpd-6rd.conf | 22 | ||||
-rwxr-xr-x | test/test-network/systemd-networkd-tests.py | 128 |
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', |