From: Yu Watanabe Date: Thu, 11 Feb 2021 17:56:43 +0000 (+0900) Subject: network: address: also set IFA_FLAGS on remove X-Git-Tag: v248-rc1~146^2~2 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=a8481354f0cd2c0855472193d0f57c7a77674969;p=thirdparty%2Fsystemd.git 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. --- diff --git a/src/network/networkd-address.c b/src/network/networkd-address.c index d7fbb6eac53..c3e92d98719 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)