diff options
author | Yu Watanabe <watanabe.yu+github@gmail.com> | 2021-05-23 23:47:19 +0900 |
---|---|---|
committer | Yu Watanabe <watanabe.yu+github@gmail.com> | 2021-06-08 06:33:27 +0900 |
commit | b9bf3f22a8f644d66c282d376758f99096ba5d81 (patch) | |
tree | b89beb074c282fc92b665373b35e82b5d6d2d9f0 | |
parent | f0269653e98885e41ffec37cae76f3820a199a18 (diff) | |
download | systemd-b9bf3f22a8f644d66c282d376758f99096ba5d81.tar.gz |
network: introduces link_drop_ipv6ll_addresses()
It is not necessary to parse whole message and store the address in
Link::addresses_foreign, as the address will be removed soon later.
-rw-r--r-- | src/network/networkd-address.c | 64 | ||||
-rw-r--r-- | src/network/networkd-address.h | 1 |
2 files changed, 49 insertions, 16 deletions
diff --git a/src/network/networkd-address.c b/src/network/networkd-address.c index 06c5c39f1c..dac799ee51 100644 --- a/src/network/networkd-address.c +++ b/src/network/networkd-address.c @@ -784,7 +784,7 @@ bool link_address_is_dynamic(const Link *link, const Address *address) { return false; } -static int link_enumerate_ipv6_tentative_addresses(Link *link) { +int link_drop_ipv6ll_addresses(Link *link) { _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL; int r; @@ -792,6 +792,12 @@ static int link_enumerate_ipv6_tentative_addresses(Link *link) { assert(link->manager); assert(link->manager->rtnl); + /* IPv6LL address may be in the tentative state, and in that case networkd has not received it. + * So, we need to dump all IPv6 addresses. */ + + if (link_ipv6ll_enabled(link)) + return 0; + r = sd_rtnl_message_new_addr(link->manager->rtnl, &req, RTM_GETADDR, link->ifindex, AF_INET6); if (r < 0) return r; @@ -805,27 +811,57 @@ static int link_enumerate_ipv6_tentative_addresses(Link *link) { return r; for (sd_netlink_message *addr = reply; addr; addr = sd_netlink_message_next(addr)) { - unsigned char flags; + _cleanup_(address_freep) Address *a = NULL; + unsigned char flags, prefixlen; + struct in6_addr address; int ifindex; /* NETLINK_GET_STRICT_CHK socket option is supported since kernel 4.20. To support * older kernels, we need to check ifindex here. */ r = sd_rtnl_message_addr_get_ifindex(addr, &ifindex); if (r < 0) { - log_link_warning_errno(link, r, "rtnl: received address message without valid ifindex, ignoring: %m"); + log_link_debug_errno(link, r, "rtnl: received address message without valid ifindex, ignoring: %m"); continue; } else if (link->ifindex != ifindex) continue; r = sd_rtnl_message_addr_get_flags(addr, &flags); if (r < 0) { - log_link_warning_errno(link, r, "rtnl: received address message without valid flags, ignoring: %m"); + log_link_debug_errno(link, r, "rtnl: received address message without valid flags, ignoring: %m"); continue; - } else if (!(flags & IFA_F_TENTATIVE)) + } + + r = sd_rtnl_message_addr_get_prefixlen(addr, &prefixlen); + if (r < 0) { + log_link_debug_errno(link, r, "rtnl: received address message without prefixlen, ignoring: %m"); continue; + } + + if (sd_netlink_message_read_in6_addr(addr, IFA_LOCAL, NULL) >= 0) + /* address with peer, ignoring. */ + continue; + + r = sd_netlink_message_read_in6_addr(addr, IFA_ADDRESS, &address); + if (r < 0) { + log_link_debug_errno(link, r, "rtnl: received address message without valid address, ignoring: %m"); + continue; + } + + if (!in6_addr_is_link_local(&address)) + continue; - log_link_debug(link, "Found tentative ipv6 link-local address"); - (void) manager_rtnl_process_address(link->manager->rtnl, addr, link->manager); + r = address_new(&a); + if (r < 0) + return -ENOMEM; + + a->family = AF_INET6; + a->in_addr.in6 = address; + a->prefixlen = prefixlen; + a->flags = flags; + + r = address_remove(a, link); + if (r < 0) + return r; } return 0; @@ -837,17 +873,13 @@ int link_drop_foreign_addresses(Link *link) { assert(link); - /* The kernel doesn't notify us about tentative addresses; - * so if ipv6ll is disabled, we need to enumerate them now so we can drop them below */ - if (!link_ipv6ll_enabled(link)) { - r = link_enumerate_ipv6_tentative_addresses(link); - if (r < 0) - return r; - } + r = link_drop_ipv6ll_addresses(link); + if (r < 0) + return log_link_warning_errno(link, r, "Failed to drop IPv6LL address: %m"); SET_FOREACH(address, link->addresses_foreign) { - /* we consider IPv6LL addresses to be managed by the kernel */ - if (address->family == AF_INET6 && in6_addr_is_link_local(&address->in_addr.in6) == 1 && link_ipv6ll_enabled(link)) + /* We consider IPv6LL addresses to be managed by the kernel, or dropped in link_drop_ipv6ll_addresses() */ + if (address->family == AF_INET6 && in6_addr_is_link_local(&address->in_addr.in6) == 1) continue; if (link_address_is_dynamic(link, address)) { diff --git a/src/network/networkd-address.h b/src/network/networkd-address.h index af9f05c1e9..56251089d1 100644 --- a/src/network/networkd-address.h +++ b/src/network/networkd-address.h @@ -64,6 +64,7 @@ DEFINE_NETWORK_SECTION_FUNCTIONS(Address, address_free); int link_drop_addresses(Link *link); int link_drop_foreign_addresses(Link *link); +int link_drop_ipv6ll_addresses(Link *link); bool link_address_is_dynamic(const Link *link, const Address *address); int link_get_ipv6_address(Link *link, const struct in6_addr *address, Address **ret); int link_get_ipv4_address(Link *link, const struct in_addr *address, unsigned char prefixlen, Address **ret); |