From a8481354f0cd2c0855472193d0f57c7a77674969 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Fri, 12 Feb 2021 02:56:43 +0900 Subject: [PATCH 1/3] network: address: also set IFA_FLAGS on remove If an address is assigned with IFA_F_MANAGETEMPADDR, then the flag must be also set on remove. Otherwise, temporary addresses will not be removed. See also inet6_rtm_deladdr() in kernel's net/ipv6/addrconf.c. Fixes #13218. --- src/network/networkd-address.c | 61 +++++++++++++++++++++------------- 1 file changed, 37 insertions(+), 24 deletions(-) diff --git a/src/network/networkd-address.c b/src/network/networkd-address.c index d7fbb6eac5..c3e92d9871 100644 --- a/src/network/networkd-address.c +++ b/src/network/networkd-address.c @@ -517,6 +517,39 @@ static int address_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, Link return 1; } +static int address_set_netlink_message(const Address *address, sd_netlink_message *req, Link *link) { + uint32_t flags; + int r; + + assert(address); + assert(req); + assert(link); + + r = sd_rtnl_message_addr_set_prefixlen(req, address->prefixlen); + if (r < 0) + return log_link_error_errno(link, r, "Could not set prefixlen: %m"); + + /* On remove, only IFA_F_MANAGETEMPADDR flag for IPv6 addresses are used. But anyway, set all + * flags here unconditionally. Without setting the flag, the template addresses generated by + * kernel will not be removed automatically when the main address is removed. */ + flags = address->flags | IFA_F_PERMANENT; + r = sd_rtnl_message_addr_set_flags(req, flags & 0xff); + if (r < 0) + return log_link_error_errno(link, r, "Could not set flags: %m"); + + if (flags & ~0xff) { + r = sd_netlink_message_append_u32(req, IFA_FLAGS, flags); + if (r < 0) + return log_link_error_errno(link, r, "Could not set extended flags: %m"); + } + + r = netlink_message_append_in_addr_union(req, IFA_LOCAL, address->family, &address->in_addr); + if (r < 0) + return log_link_error_errno(link, r, "Could not append IFA_LOCAL attribute: %m"); + + return 0; +} + int address_remove( const Address *address, Link *link, @@ -539,13 +572,9 @@ int address_remove( if (r < 0) return log_link_error_errno(link, r, "Could not allocate RTM_DELADDR message: %m"); - r = sd_rtnl_message_addr_set_prefixlen(req, address->prefixlen); + r = address_set_netlink_message(address, req, link); if (r < 0) - return log_link_error_errno(link, r, "Could not set prefixlen: %m"); - - r = netlink_message_append_in_addr_union(req, IFA_LOCAL, address->family, &address->in_addr); - if (r < 0) - return log_link_error_errno(link, r, "Could not append IFA_LOCAL attribute: %m"); + return r; r = netlink_call_async(link->manager->rtnl, NULL, req, callback ?: address_remove_handler, @@ -809,7 +838,6 @@ int address_configure( _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; Address *acquired_address, *a; - uint32_t flags; bool update; int r; @@ -846,29 +874,14 @@ int address_configure( if (r < 0) return log_link_error_errno(link, r, "Could not allocate RTM_NEWADDR message: %m"); - r = sd_rtnl_message_addr_set_prefixlen(req, address->prefixlen); + r = address_set_netlink_message(address, req, link); if (r < 0) - return log_link_error_errno(link, r, "Could not set prefixlen: %m"); - - flags = address->flags | IFA_F_PERMANENT; - r = sd_rtnl_message_addr_set_flags(req, flags & 0xff); - if (r < 0) - return log_link_error_errno(link, r, "Could not set flags: %m"); - - if (flags & ~0xff) { - r = sd_netlink_message_append_u32(req, IFA_FLAGS, flags); - if (r < 0) - return log_link_error_errno(link, r, "Could not set extended flags: %m"); - } + return r; r = sd_rtnl_message_addr_set_scope(req, address->scope); if (r < 0) return log_link_error_errno(link, r, "Could not set scope: %m"); - r = netlink_message_append_in_addr_union(req, IFA_LOCAL, address->family, &address->in_addr); - if (r < 0) - return log_link_error_errno(link, r, "Could not append IFA_LOCAL attribute: %m"); - if (in_addr_is_null(address->family, &address->in_addr_peer) == 0) { r = netlink_message_append_in_addr_union(req, IFA_ADDRESS, address->family, &address->in_addr_peer); if (r < 0) From 53ae4762efb37e1b6ea1139eca836c53af61293d Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Fri, 12 Feb 2021 14:44:42 +0900 Subject: [PATCH 2/3] network: address: do not set IFA_F_PERMANENT flag The flag is automatically set by kernel when the valid lifetime is infinite. Note that the flag in netlink message for IPv4 address is ignored. See set_ifa_lifetime() in kernel's net/ipv4/devinet.c. But the flag is honored for IPv6 address. And if the flag is set with finite valid lifetime, the address will not removed automatically by the kernel. --- src/network/networkd-address.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/network/networkd-address.c b/src/network/networkd-address.c index c3e92d9871..d857b6d879 100644 --- a/src/network/networkd-address.c +++ b/src/network/networkd-address.c @@ -518,7 +518,6 @@ static int address_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, Link } static int address_set_netlink_message(const Address *address, sd_netlink_message *req, Link *link) { - uint32_t flags; int r; assert(address); @@ -532,13 +531,12 @@ static int address_set_netlink_message(const Address *address, sd_netlink_messag /* On remove, only IFA_F_MANAGETEMPADDR flag for IPv6 addresses are used. But anyway, set all * flags here unconditionally. Without setting the flag, the template addresses generated by * kernel will not be removed automatically when the main address is removed. */ - flags = address->flags | IFA_F_PERMANENT; - r = sd_rtnl_message_addr_set_flags(req, flags & 0xff); + r = sd_rtnl_message_addr_set_flags(req, address->flags & 0xff); if (r < 0) return log_link_error_errno(link, r, "Could not set flags: %m"); - if (flags & ~0xff) { - r = sd_netlink_message_append_u32(req, IFA_FLAGS, flags); + if ((address->flags & ~0xff) != 0) { + r = sd_netlink_message_append_u32(req, IFA_FLAGS, address->flags); if (r < 0) return log_link_error_errno(link, r, "Could not set extended flags: %m"); } From 4a70450104b6237912ba52741f1d2a8ba16028de Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Fri, 12 Feb 2021 15:01:20 +0900 Subject: [PATCH 3/3] test-network: merge test_address_static and test_address_preferred_lifetime_zero_ipv6 --- ...25-address-preferred-lifetime-zero.network | 35 ------------- .../conf/25-address-static.network | 9 ++++ test/test-network/systemd-networkd-tests.py | 52 +++++++------------ 3 files changed, 28 insertions(+), 68 deletions(-) delete mode 100644 test/test-network/conf/25-address-preferred-lifetime-zero.network diff --git a/test/test-network/conf/25-address-preferred-lifetime-zero.network b/test/test-network/conf/25-address-preferred-lifetime-zero.network deleted file mode 100644 index d3d02d282f..0000000000 --- a/test/test-network/conf/25-address-preferred-lifetime-zero.network +++ /dev/null @@ -1,35 +0,0 @@ -[Match] -Name=dummy98 - -[Network] -IPv6AcceptRA=no - -# these lines are ignored -Address=hogehoge -Address=foofoo - -[Route] -Gateway=20.20.20.1 - -[Address] -Address=10.2.3.4/16 -PreferredLifetime=0 -Scope=link - -[Address] -Address=2001:0db8:0:f101::1/64 - -[Address] -Address=20.20.20.100/24 - -[Address] -# this section must be ignored -Peer=hoge -Address=10.10.0.1/16 -Label=30 - -[Address] -# this section must be ignored -Label=30 -Peer=hoge -Address=10.10.0.2/16 diff --git a/test/test-network/conf/25-address-static.network b/test/test-network/conf/25-address-static.network index 506cdd2264..da57bf7351 100644 --- a/test/test-network/conf/25-address-static.network +++ b/test/test-network/conf/25-address-static.network @@ -52,6 +52,15 @@ Peer=2001:db8:0:f103::10/128 [Address] Address=::/64 +[Address] +Address=10.7.8.9/16 +PreferredLifetime=0 +Scope=link + +[Address] +Address=2001:0db8:1:f101::1/64 +PreferredLifetime=0 + # test for ENOBUFS issue #17012 [Network] Address=10.3.3.1/16 diff --git a/test/test-network/systemd-networkd-tests.py b/test/test-network/systemd-networkd-tests.py index 5179b93643..0740003ed3 100755 --- a/test/test-network/systemd-networkd-tests.py +++ b/test/test-network/systemd-networkd-tests.py @@ -1753,7 +1753,6 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities): '25-address-dad-veth99.network', '25-address-link-section.network', '25-address-peer-ipv4.network', - '25-address-preferred-lifetime-zero.network', '25-address-static.network', '25-activation-policy.network', '25-bind-carrier.network', @@ -1830,38 +1829,40 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities): output = check_output('ip -4 address show dev dummy98') print(output) - self.assertRegex(output, 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98') - self.assertRegex(output, 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98') - self.assertRegex(output, 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98') + self.assertIn('inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98', output) + self.assertIn('inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98', output) + self.assertIn('inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98', output) + self.assertIn('inet 10.7.8.9/16 brd 10.7.255.255 scope link deprecated dummy98', output) # test for ENOBUFS issue #17012 for i in range(1,254): - self.assertRegex(output, f'inet 10.3.3.{i}/16 brd 10.3.255.255') + self.assertIn(f'inet 10.3.3.{i}/16 brd 10.3.255.255', output) # invalid sections - self.assertNotRegex(output, '10.10.0.1/16') - self.assertNotRegex(output, '10.10.0.2/16') + self.assertNotIn('10.10.0.1/16', output) + self.assertNotIn('10.10.0.2/16', output) output = check_output('ip -4 address show dev dummy98 label 32') - self.assertRegex(output, 'inet 10.3.2.3/16 brd 10.3.255.255 scope global 32') + self.assertIn('inet 10.3.2.3/16 brd 10.3.255.255 scope global 32', output) output = check_output('ip -4 address show dev dummy98 label 33') - self.assertRegex(output, 'inet 10.4.2.3 peer 10.4.2.4/16 scope global 33') + self.assertIn('inet 10.4.2.3 peer 10.4.2.4/16 scope global 33', output) output = check_output('ip -4 address show dev dummy98 label 34') - self.assertRegex(output, 'inet 192.168.[0-9]*.1/24 brd 192.168.[0-9]*.255 scope global 34') + self.assertRegex(output, r'inet 192.168.[0-9]*.1/24 brd 192.168.[0-9]*.255 scope global 34') output = check_output('ip -4 address show dev dummy98 label 35') - self.assertRegex(output, 'inet 172.[0-9]*.0.1/16 brd 172.[0-9]*.255.255 scope global 35') + self.assertRegex(output, r'inet 172.[0-9]*.0.1/16 brd 172.[0-9]*.255.255 scope global 35') output = check_output('ip -6 address show dev dummy98') print(output) - self.assertRegex(output, 'inet6 2001:db8:0:f101::15/64 scope global') - self.assertRegex(output, 'inet6 2001:db8:0:f101::16/64 scope global') - self.assertRegex(output, 'inet6 2001:db8:0:f102::15/64 scope global') - self.assertRegex(output, 'inet6 2001:db8:0:f102::16/64 scope global') - self.assertRegex(output, 'inet6 2001:db8:0:f103::20 peer 2001:db8:0:f103::10/128 scope global') - self.assertRegex(output, 'inet6 fd[0-9a-f:]*1/64 scope global') + self.assertIn('inet6 2001:db8:0:f101::15/64 scope global', output) + self.assertIn('inet6 2001:db8:0:f101::16/64 scope global', output) + self.assertIn('inet6 2001:db8:0:f102::15/64 scope global', output) + self.assertIn('inet6 2001:db8:0:f102::16/64 scope global', output) + self.assertIn('inet6 2001:db8:0:f103::20 peer 2001:db8:0:f103::10/128 scope global', output) + self.assertIn('inet6 2001:db8:1:f101::1/64 scope global deprecated', output) + self.assertRegex(output, r'inet6 fd[0-9a-f:]*1/64 scope global') restart_networkd() self.wait_online(['dummy98:routable']) @@ -1869,22 +1870,7 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities): # test for ENOBUFS issue #17012 output = check_output('ip -4 address show dev dummy98') for i in range(1,254): - self.assertRegex(output, f'inet 10.3.3.{i}/16 brd 10.3.255.255') - - def test_address_preferred_lifetime_zero_ipv6(self): - copy_unit_to_networkd_unit_path('25-address-preferred-lifetime-zero.network', '12-dummy.netdev') - start_networkd(5) - - self.wait_online(['dummy98:routable']) - - output = check_output('ip address show dummy98') - print(output) - self.assertRegex(output, 'inet 10.2.3.4/16 brd 10.2.255.255 scope link deprecated dummy98') - self.assertRegex(output, 'inet6 2001:db8:0:f101::1/64 scope global') - - output = check_output('ip route show dev dummy98') - print(output) - self.assertRegex(output, 'default via 20.20.20.1 proto static') + self.assertIn(f'inet 10.3.3.{i}/16 brd 10.3.255.255', output) def test_address_dad(self): copy_unit_to_networkd_unit_path('25-address-dad-veth99.network', '25-address-dad-veth-peer.network',