From ac2dce5f36bb8b1a877ff765e6a4dfde6bfb2d49 Mon Sep 17 00:00:00 2001 From: Dan Streetman Date: Fri, 5 Jul 2019 16:42:38 -0400 Subject: [PATCH 1/2] src/network/networkd-dhcp4.c: set prefsrc for classless or static routes When a DHCP server provides only a gateway, the networkd-dhcp4 code adds a default route using that gateway, and sets the just-provided address as the route's prefsrc; this was added in commit 46b0c76e2c355c0d0cc4792abb98cde07b28bc53 However, if the DHCP server has also provided classless route(s), these are used instead of a default route using the provided gateway; the networkd-dhcp4 code sets up the classless routes, but does not use the just-provided dhcp address as the prefsrc of the route(s). Note that it also doesn't set the prefsrc for static routes, though it should. If the interface has only the dhcp-provided address, this is not usually a problem, but if it has another address (e.g. a static address), then traffic sent through the dhcp-provided gateway might not use the dhcp-provided source address. If the gateway router only will route traffic from the dhcp-provided address, then the dhcp client system's networking through the router will not work. Fixes: #12969 --- src/network/networkd-dhcp4.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/network/networkd-dhcp4.c b/src/network/networkd-dhcp4.c index 3e384a47c0..c0d776f464 100644 --- a/src/network/networkd-dhcp4.c +++ b/src/network/networkd-dhcp4.c @@ -147,6 +147,8 @@ static int link_set_dhcp_routes(Link *link) { route->priority = link->network->dhcp_route_metric; route->table = table; route->scope = route_scope_from_address(route, &address); + if (IN_SET(route->scope, RT_SCOPE_LINK, RT_SCOPE_UNIVERSE)) + route->prefsrc.in = address; r = route_configure(route, link, dhcp4_route_handler); if (r < 0) @@ -277,6 +279,8 @@ static int dhcp_remove_routes(Link *link, sd_dhcp_lease *lease, sd_dhcp_lease *n route->priority = link->network->dhcp_route_metric; route->table = table; route->scope = route_scope_from_address(route, address); + if (IN_SET(route->scope, RT_SCOPE_LINK, RT_SCOPE_UNIVERSE)) + route->prefsrc.in = *address; if (route_present_in_routes(route, new_routes, m)) continue; From 4c882c16beb3e72f7d1ee94b75a9b778b0dde14b Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sat, 6 Jul 2019 07:39:17 +0900 Subject: [PATCH 2/2] test-network: add testcase for DHCP client with static address Testcase for #12969. --- .../dhcp-client-with-static-address.network | 7 +++++++ test/test-network/systemd-networkd-tests.py | 21 +++++++++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 test/test-network/conf/dhcp-client-with-static-address.network diff --git a/test/test-network/conf/dhcp-client-with-static-address.network b/test/test-network/conf/dhcp-client-with-static-address.network new file mode 100644 index 0000000000..b4e11bea09 --- /dev/null +++ b/test/test-network/conf/dhcp-client-with-static-address.network @@ -0,0 +1,7 @@ +[Match] +Name=veth99 + +[Network] +DHCP=ipv4 +IPv6AcceptRA=no +Address=192.168.5.250 diff --git a/test/test-network/systemd-networkd-tests.py b/test/test-network/systemd-networkd-tests.py index ba8fb7255f..fb91b2f897 100755 --- a/test/test-network/systemd-networkd-tests.py +++ b/test/test-network/systemd-networkd-tests.py @@ -2122,6 +2122,7 @@ class NetworkdDHCPClientTests(unittest.TestCase, Utilities): 'dhcp-client-vrf.network', 'dhcp-client-with-ipv4ll-fallback-with-dhcp-server.network', 'dhcp-client-with-ipv4ll-fallback-without-dhcp-server.network', + 'dhcp-client-with-static-address.network', 'dhcp-client.network', 'dhcp-server-veth-peer.network', 'dhcp-v4-server-veth-peer.network', @@ -2272,6 +2273,26 @@ class NetworkdDHCPClientTests(unittest.TestCase, Utilities): print(output) self.assertRegex(output, '192.168.5.* dynamic') + def test_dhcp_client_with_static_address(self): + copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', + 'dhcp-client-with-static-address.network') + start_networkd() + wait_online(['veth-peer:carrier']) + start_dnsmasq() + wait_online(['veth99:routable', 'veth-peer:routable']) + + output = check_output('ip address show dev veth99 scope global') + print(output) + self.assertRegex(output, r'inet 192.168.5.250/24 brd 192.168.5.255 scope global veth99') + self.assertRegex(output, r'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global secondary dynamic veth99') + + output = check_output('ip route show dev veth99') + print(output) + self.assertRegex(output, r'default via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024') + self.assertRegex(output, r'192.168.5.0/24 proto kernel scope link src 192.168.5.250') + self.assertRegex(output, r'192.168.5.0/24 via 192.168.5.5 proto dhcp src 192.168.5.[0-9]* metric 1024') + self.assertRegex(output, r'192.168.5.1 proto dhcp scope link src 192.168.5.[0-9]* metric 1024') + def test_dhcp_route_table_id(self): copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-route-table.network') start_networkd()