From 11046cea1414c70b5d7aab37ea88d5a839cbd209 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Mon, 12 Jul 2021 15:46:44 +0900 Subject: [PATCH 1/2] network: also check addresses when determine a gateway address is reachable or not Fixes #20201. --- src/network/networkd-route.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/src/network/networkd-route.c b/src/network/networkd-route.c index 7b36b481419..0ab4419eba9 100644 --- a/src/network/networkd-route.c +++ b/src/network/networkd-route.c @@ -746,6 +746,26 @@ static bool route_address_is_reachable(const Route *route, int family, const uni FAMILY_ADDRESS_SIZE(family) * 8) > 0; } +static bool prefix_route_address_is_reachable(const Address *a, int family, const union in_addr_union *address) { + assert(a); + assert(IN_SET(family, AF_INET, AF_INET6)); + assert(address); + + if (a->family != family) + return false; + if (FLAGS_SET(a->flags, IFA_F_NOPREFIXROUTE)) + return false; + if (in_addr_is_set(a->family, &a->in_addr_peer)) + return false; + + return in_addr_prefix_intersect( + family, + &a->in_addr, + a->prefixlen, + address, + FAMILY_ADDRESS_SIZE(family) * 8) > 0; +} + bool manager_address_is_reachable(Manager *manager, int family, const union in_addr_union *address) { Link *link; @@ -764,6 +784,20 @@ bool manager_address_is_reachable(Manager *manager, int family, const union in_a return true; } + /* If we do not manage foreign routes, then there may exist a prefix route we do not know, + * which was created on configuring an address. Hence, also check the addresses. */ + if (!manager->manage_foreign_routes) + HASHMAP_FOREACH(link, manager->links_by_index) { + Address *a; + + SET_FOREACH(a, link->addresses) + if (prefix_route_address_is_reachable(a, family, address)) + return true; + SET_FOREACH(a, link->addresses_foreign) + if (prefix_route_address_is_reachable(a, family, address)) + return true; + } + return false; } From 1d26d4cd140e939babf83425cdcaef4ca4bc82ce Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Mon, 12 Jul 2021 16:36:55 +0900 Subject: [PATCH 2/2] test-network: add a testcase for ManageForeignRoutes=no --- .../networkd-manage-foreign-routes-no.conf | 2 ++ test/test-network/systemd-networkd-tests.py | 30 ++++++++++++++++++- 2 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 test/test-network/conf/networkd-manage-foreign-routes-no.conf diff --git a/test/test-network/conf/networkd-manage-foreign-routes-no.conf b/test/test-network/conf/networkd-manage-foreign-routes-no.conf new file mode 100644 index 00000000000..c75b8b45b9e --- /dev/null +++ b/test/test-network/conf/networkd-manage-foreign-routes-no.conf @@ -0,0 +1,2 @@ +[Network] +ManageForeignRoutes=no diff --git a/test/test-network/systemd-networkd-tests.py b/test/test-network/systemd-networkd-tests.py index 4279b612d0f..884bb6a650d 100755 --- a/test/test-network/systemd-networkd-tests.py +++ b/test/test-network/systemd-networkd-tests.py @@ -16,6 +16,7 @@ from shutil import copytree network_unit_file_path='/run/systemd/network' networkd_runtime_directory='/run/systemd/netif' +networkd_conf_dropin_path='/run/systemd/networkd.conf.d' networkd_ci_path='/run/networkd-ci' network_sysctl_ipv6_path='/proc/sys/net/ipv6/conf' network_sysctl_ipv4_path='/proc/sys/net/ipv4/conf' @@ -263,6 +264,7 @@ def setUpModule(): global running_units os.makedirs(network_unit_file_path, exist_ok=True) + os.makedirs(networkd_conf_dropin_path, exist_ok=True) os.makedirs(networkd_ci_path, exist_ok=True) shutil.rmtree(networkd_ci_path) @@ -460,6 +462,17 @@ def remove_unit_from_networkd_path(units): if (os.path.exists(os.path.join(network_unit_file_path, unit + '.d'))): shutil.rmtree(os.path.join(network_unit_file_path, unit + '.d')) +def copy_networkd_conf_dropin(*dropins): + """Copy networkd.conf dropin files into the testbed.""" + for dropin in dropins: + shutil.copy(os.path.join(networkd_ci_path, dropin), networkd_conf_dropin_path) + +def remove_networkd_conf_dropin(dropins): + """Remove previously copied networkd.conf dropin files from the testbed.""" + for dropin in 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 /var/run/networkd-ci/test-dnsmasq-log-file --log-queries=extra --log-dhcp --pid-file=/var/run/networkd-ci/test-test-dnsmasq.pid --conf-file=/dev/null --interface=veth-peer --enable-ra --dhcp-range={ipv6_range},{lease_time} --dhcp-range={ipv4_range},{lease_time} -R --dhcp-leasefile=/var/run/networkd-ci/lease --dhcp-option=26,1492 --dhcp-option=option:router,192.168.5.1 --port=0 ' + additional_options check_output(dnsmasq_command) @@ -1858,6 +1871,10 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities): 'routing-policy-rule-reconfigure2.network', ] + networkd_conf_dropins = [ + 'networkd-manage-foreign-routes-no.conf', + ] + routing_policy_rule_tables = ['7', '8', '9', '10', '1011'] routes = [['blackhole', '202.54.1.2'], ['unreachable', '202.54.1.3'], ['prohibit', '202.54.1.4']] @@ -1875,6 +1892,7 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities): remove_routes(self.routes) remove_links(self.links) remove_unit_from_networkd_path(self.units) + remove_networkd_conf_dropin(self.networkd_conf_dropins) stop_networkd(show_logs=True) call('ip netns del ns99', stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) @@ -2253,7 +2271,10 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities): self.assertRegex(output, 'lookup 7') self.assertRegex(output, 'uidrange 100-200') - def test_route_static(self): + def _test_route_static(self, manage_foreign_routes): + if not manage_foreign_routes: + copy_networkd_conf_dropin('networkd-manage-foreign-routes-no.conf') + copy_unit_to_networkd_unit_path('25-route-static.network', '12-dummy.netdev') start_networkd() self.wait_online(['dummy98:routable']) @@ -2459,6 +2480,13 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities): print(output) self.assertEqual(output, '') + self.tearDown() + + def test_route_static(self): + for manage_foreign_routes in [True, False]: + with self.subTest(manage_foreign_routes=manage_foreign_routes): + self._test_route_static(manage_foreign_routes) + @expectedFailureIfRTA_VIAIsNotSupported() def test_route_via_ipv6(self): copy_unit_to_networkd_unit_path('25-route-via-ipv6.network', '12-dummy.netdev')