diff --git a/src/network/netdev/tunnel.c b/src/network/netdev/tunnel.c index 94e3a1fe291..26f7f207da1 100644 --- a/src/network/netdev/tunnel.c +++ b/src/network/netdev/tunnel.c @@ -34,7 +34,7 @@ DEFINE_CONFIG_PARSE_ENUM(config_parse_ip6tnl_mode, ip6tnl_mode, Ip6TnlMode); #define HASH_KEY SD_ID128_MAKE(74,c4,de,12,f3,d9,41,34,bb,3d,c1,a4,42,93,50,87) -int dhcp4_pd_create_6rd_tunnel_name(Link *link, char **ret) { +static int dhcp4_pd_create_6rd_tunnel_name(Link *link) { _cleanup_free_ char *ifname_alloc = NULL; uint8_t ipv4masklen, sixrd_prefixlen, *buf, *p; struct in_addr ipv4address; @@ -47,13 +47,16 @@ int dhcp4_pd_create_6rd_tunnel_name(Link *link, char **ret) { assert(link); assert(link->dhcp_lease); + if (link->dhcp4_6rd_tunnel_name) + return 0; /* Already set. Do not change even if the 6rd option is changed. */ + r = sd_dhcp_lease_get_address(link->dhcp_lease, &ipv4address); if (r < 0) - return log_link_debug_errno(link, r, "Failed to get DHCPv4 address: %m"); + return r; r = sd_dhcp_lease_get_6rd(link->dhcp_lease, &ipv4masklen, &sixrd_prefixlen, &sixrd_prefix, NULL, NULL); if (r < 0) - return log_link_debug_errno(link, r, "Failed to get 6rd option: %m"); + return r; sz = sizeof(uint8_t) * 2 + sizeof(struct in6_addr) + sizeof(struct in_addr); buf = newa(uint8_t, sz); @@ -80,21 +83,44 @@ int dhcp4_pd_create_6rd_tunnel_name(Link *link, char **ret) { ifname_alloc = strdup(ifname); if (!ifname_alloc) - return log_oom_debug(); + return -ENOMEM; - *ret = TAKE_PTR(ifname_alloc); + link->dhcp4_6rd_tunnel_name = TAKE_PTR(ifname_alloc); return 0; } -static int dhcp4_pd_create_6rd_tunnel_message( - Link *link, - sd_netlink_message *m, - const struct in_addr *ipv4address, - uint8_t ipv4masklen, - const struct in6_addr *sixrd_prefix, - uint8_t sixrd_prefixlen) { +int dhcp4_pd_create_6rd_tunnel(Link *link, link_netlink_message_handler_t callback) { + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; + uint8_t ipv4masklen, sixrd_prefixlen; + struct in_addr ipv4address; + struct in6_addr sixrd_prefix; + Link *sit = NULL; int r; + assert(link); + assert(link->manager); + assert(link->manager->rtnl); + assert(link->dhcp_lease); + assert(callback); + + r = sd_dhcp_lease_get_address(link->dhcp_lease, &ipv4address); + if (r < 0) + return r; + + r = sd_dhcp_lease_get_6rd(link->dhcp_lease, &ipv4masklen, &sixrd_prefixlen, &sixrd_prefix, NULL, NULL); + if (r < 0) + return r; + + r = dhcp4_pd_create_6rd_tunnel_name(link); + if (r < 0) + return r; + + (void) link_get_by_name(link->manager, link->dhcp4_6rd_tunnel_name, &sit); + + r = sd_rtnl_message_new_link(link->manager->rtnl, &m, RTM_NEWLINK, sit ? sit->ifindex : 0); + if (r < 0) + return r; + r = sd_netlink_message_append_string(m, IFLA_IFNAME, link->dhcp4_6rd_tunnel_name); if (r < 0) return r; @@ -107,7 +133,7 @@ static int dhcp4_pd_create_6rd_tunnel_message( if (r < 0) return r; - r = sd_netlink_message_append_in_addr(m, IFLA_IPTUN_LOCAL, ipv4address); + r = sd_netlink_message_append_in_addr(m, IFLA_IPTUN_LOCAL, &ipv4address); if (r < 0) return r; @@ -115,7 +141,7 @@ static int dhcp4_pd_create_6rd_tunnel_message( if (r < 0) return r; - r = sd_netlink_message_append_in6_addr(m, IFLA_IPTUN_6RD_PREFIX, sixrd_prefix); + r = sd_netlink_message_append_in6_addr(m, IFLA_IPTUN_6RD_PREFIX, &sixrd_prefix); if (r < 0) return r; @@ -123,7 +149,7 @@ static int dhcp4_pd_create_6rd_tunnel_message( if (r < 0) return r; - struct in_addr relay_prefix = *ipv4address; + struct in_addr relay_prefix = ipv4address; (void) in4_addr_mask(&relay_prefix, ipv4masklen); r = sd_netlink_message_append_u32(m, IFLA_IPTUN_6RD_RELAY_PREFIX, relay_prefix.s_addr); if (r < 0) @@ -141,48 +167,12 @@ static int dhcp4_pd_create_6rd_tunnel_message( if (r < 0) return r; - return 0; -} - -int dhcp4_pd_create_6rd_tunnel(Link *link, link_netlink_message_handler_t callback) { - _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; - uint8_t ipv4masklen, sixrd_prefixlen; - struct in_addr ipv4address; - struct in6_addr sixrd_prefix; - int r; - - assert(link); - assert(link->ifindex > 0); - assert(link->manager); - assert(link->dhcp_lease); - assert(link->dhcp4_6rd_tunnel_name); - assert(callback); - - r = sd_dhcp_lease_get_address(link->dhcp_lease, &ipv4address); - if (r < 0) - return log_link_debug_errno(link, r, "Failed to get DHCPv4 address: %m"); - - r = sd_dhcp_lease_get_6rd(link->dhcp_lease, &ipv4masklen, &sixrd_prefixlen, &sixrd_prefix, NULL, NULL); - if (r < 0) - return log_link_debug_errno(link, r, "Failed to get 6rd option: %m"); - - r = sd_rtnl_message_new_link(link->manager->rtnl, &m, RTM_NEWLINK, 0); - if (r < 0) - return log_link_debug_errno(link, r, "Failed to create netlink message: %m"); - - r = dhcp4_pd_create_6rd_tunnel_message(link, m, - &ipv4address, ipv4masklen, - &sixrd_prefix, sixrd_prefixlen); - if (r < 0) - return log_link_debug_errno(link, r, "Failed to fill netlink message: %m"); - r = netlink_call_async(link->manager->rtnl, NULL, m, callback, link_netlink_destroy_callback, link); if (r < 0) - return log_link_debug_errno(link, r, "Could not send netlink message: %m"); + return r; link_ref(link); - return 0; } diff --git a/src/network/netdev/tunnel.h b/src/network/netdev/tunnel.h index cf26cfad98e..6cd03b032d2 100644 --- a/src/network/netdev/tunnel.h +++ b/src/network/netdev/tunnel.h @@ -69,7 +69,6 @@ typedef struct Tunnel { uint8_t sixrd_prefixlen; } Tunnel; -int dhcp4_pd_create_6rd_tunnel_name(Link *link, char **ret); int dhcp4_pd_create_6rd_tunnel(Link *link, link_netlink_message_handler_t callback); DEFINE_NETDEV_CAST(IPIP, Tunnel); diff --git a/src/network/networkd-dhcp-prefix-delegation.c b/src/network/networkd-dhcp-prefix-delegation.c index 56555df62c7..1f80513007c 100644 --- a/src/network/networkd-dhcp-prefix-delegation.c +++ b/src/network/networkd-dhcp-prefix-delegation.c @@ -961,7 +961,6 @@ static int dhcp4_pd_6rd_tunnel_create_handler(sd_netlink *rtnl, sd_netlink_messa } int dhcp4_pd_prefix_acquired(Link *uplink) { - _cleanup_free_ char *tunnel_name = NULL; uint8_t ipv4masklen, sixrd_prefixlen, pd_prefixlen; struct in6_addr sixrd_prefix, pd_prefix; struct in_addr ipv4address; @@ -1010,28 +1009,10 @@ int dhcp4_pd_prefix_acquired(Link *uplink) { if (r < 0) return r; - /* Generate 6rd SIT tunnel device name. */ - r = dhcp4_pd_create_6rd_tunnel_name(uplink, &tunnel_name); + /* Create or update 6rd SIT tunnel device. */ + r = dhcp4_pd_create_6rd_tunnel(uplink, dhcp4_pd_6rd_tunnel_create_handler); if (r < 0) - return r; - - /* Remove old tunnel device if exists. */ - if (!streq_ptr(uplink->dhcp4_6rd_tunnel_name, tunnel_name)) { - Link *old_tunnel; - - if (uplink->dhcp4_6rd_tunnel_name && - link_get_by_name(uplink->manager, uplink->dhcp4_6rd_tunnel_name, &old_tunnel) >= 0) - (void) link_remove(old_tunnel); - - free_and_replace(uplink->dhcp4_6rd_tunnel_name, tunnel_name); - } - - /* Create 6rd SIT tunnel device if it does not exist yet. */ - if (link_get_by_name(uplink->manager, uplink->dhcp4_6rd_tunnel_name, NULL) < 0) { - r = dhcp4_pd_create_6rd_tunnel(uplink, dhcp4_pd_6rd_tunnel_create_handler); - if (r < 0) - return r; - } + return log_link_warning_errno(uplink, r, "Failed to create or update 6rd SIT tunnel: %m"); /* Then, assign subnet prefixes to downstream interfaces. */ HASHMAP_FOREACH(link, uplink->manager->links_by_index) { diff --git a/test/test-network/systemd-networkd-tests.py b/test/test-network/systemd-networkd-tests.py index 6a14dff1444..79d593bb7e5 100755 --- a/test/test-network/systemd-networkd-tests.py +++ b/test/test-network/systemd-networkd-tests.py @@ -7732,7 +7732,7 @@ class NetworkdDHCPPDTests(unittest.TestCase, Utilities): self.teardown_nftset('addr6', 'network6', 'ifindex') - def verify_dhcp4_6rd(self, tunnel_name): + def verify_dhcp4_6rd(self, tunnel_name, address_prefix, border_router): print('### ip -4 address show dev veth-peer scope global') output = check_output('ip -4 address show dev veth-peer scope global') print(output) @@ -7751,7 +7751,7 @@ class NetworkdDHCPPDTests(unittest.TestCase, Utilities): print('### ip -4 address show dev veth99 scope global') output = check_output('ip -4 address show dev veth99 scope global') print(output) - self.assertRegex(output, 'inet 10.100.100.[0-9]*/8 (metric 1024 |)brd 10.255.255.255 scope global dynamic veth99') + self.assertRegex(output, fr'inet {address_prefix}[0-9]*/8 (metric 1024 |)brd 10.255.255.255 scope global dynamic veth99') print('### ip -6 address show dev veth99 scope global') output = check_output('ip -6 address show dev veth99 scope global') @@ -7887,8 +7887,8 @@ class NetworkdDHCPPDTests(unittest.TestCase, Utilities): print(f'### ip -d link show dev {tunnel_name}') output = check_output(f'ip -d link show dev {tunnel_name}') print(output) - self.assertIn('link/sit 10.100.100.', output) - self.assertIn('local 10.100.100.', output) + self.assertIn(f'link/sit {address_prefix}', output) + self.assertIn(f'local {address_prefix}', 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) @@ -7897,7 +7897,7 @@ class NetworkdDHCPPDTests(unittest.TestCase, Utilities): output = check_output(f'ip -6 address show dev {tunnel_name}') print(output) self.assertRegex(output, 'inet6 2001:db8:6464:[0-9a-f]+0[23]:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*/64 (metric 256 |)scope global dynamic') - self.assertRegex(output, 'inet6 ::10.100.100.[0-9]+/96 scope global') + self.assertRegex(output, fr'inet6 ::{address_prefix}[0-9]+/96 scope global') print(f'### ip -6 route show dev {tunnel_name}') output = check_output(f'ip -6 route show dev {tunnel_name}') @@ -7909,7 +7909,7 @@ class NetworkdDHCPPDTests(unittest.TestCase, Utilities): output = check_output('ip -6 route show default') print(output) self.assertIn('default', output) - self.assertIn(f'via ::10.0.0.1 dev {tunnel_name}', output) + self.assertIn(f'via ::{border_router} dev {tunnel_name}', output) def test_dhcp4_6rd(self): def get_dhcp_6rd_prefix(link): @@ -7969,13 +7969,19 @@ class NetworkdDHCPPDTests(unittest.TestCase, Utilities): self.wait_online(f'{tunnel_name}:routable') - self.verify_dhcp4_6rd(tunnel_name) + self.verify_dhcp4_6rd(tunnel_name, '10.100.100.1', '10.0.0.1') # Test case for reconfigure networkctl_reconfigure('dummy98', 'dummy99') self.wait_online('dummy98:routable', 'dummy99:degraded') - self.verify_dhcp4_6rd(tunnel_name) + self.verify_dhcp4_6rd(tunnel_name, '10.100.100.1', '10.0.0.1') + + # Change the address range and (border) router, then if check the same tunnel is reused. + stop_dnsmasq() + start_dnsmasq('--dhcp-option=212,08:20:20:01:0d:b8:00:00:00:00:00:00:00:00:00:00:00:00:0a:00:00:02', + ipv4_range='10.100.100.200,10.100.100.250', + ipv4_router='10.0.0.2') print('Wait for the DHCP lease to be renewed/rebind') time.sleep(120) @@ -7983,7 +7989,7 @@ class NetworkdDHCPPDTests(unittest.TestCase, Utilities): 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) + self.verify_dhcp4_6rd(tunnel_name, '10.100.100.2', '10.0.0.2') class NetworkdIPv6PrefixTests(unittest.TestCase, Utilities):