From 3c283289aefb3cfb8bfa5c759209368b63d1692c Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sat, 8 Jul 2023 15:40:57 +0900 Subject: [PATCH 1/5] network/address: make Address object more consistent with assigned address This makes `manager_rtnl_process_address()` - first read minimal information to get managed Address object, - then update the managed Address object directly. Previously, we updated the Address object managed by Link partially, e.g. peer address did not updated. This makes the managed Address object more consistent with the assigned address. --- src/network/networkd-address.c | 150 +++++++++++++++------------------ 1 file changed, 69 insertions(+), 81 deletions(-) diff --git a/src/network/networkd-address.c b/src/network/networkd-address.c index 1f356907fe..e9959486a7 100644 --- a/src/network/networkd-address.c +++ b/src/network/networkd-address.c @@ -1464,6 +1464,7 @@ int manager_rtnl_process_address(sd_netlink *rtnl, sd_netlink_message *message, Link *link; uint16_t type; Address *address = NULL; + bool is_new = false; int ifindex, r; assert(rtnl); @@ -1509,6 +1510,8 @@ int manager_rtnl_process_address(sd_netlink *rtnl, sd_netlink_message *message, if (r < 0) return log_oom(); + /* First, read minimal information to make address_get() work below. */ + r = sd_rtnl_message_addr_get_family(message, &tmp->family); if (r < 0) { log_link_warning(link, "rtnl: received address message without family, ignoring."); @@ -1524,26 +1527,6 @@ int manager_rtnl_process_address(sd_netlink *rtnl, sd_netlink_message *message, return 0; } - r = sd_rtnl_message_addr_get_scope(message, &tmp->scope); - if (r < 0) { - log_link_warning_errno(link, r, "rtnl: received address message without scope, ignoring: %m"); - return 0; - } - - r = sd_netlink_message_read_u32(message, IFA_FLAGS, &tmp->flags); - if (r == -ENODATA) { - unsigned char flags; - - /* For old kernels. */ - r = sd_rtnl_message_addr_get_flags(message, &flags); - if (r >= 0) - tmp->flags = flags; - } - if (r < 0) { - log_link_warning_errno(link, r, "rtnl: received address message without flags, ignoring: %m"); - return 0; - } - switch (tmp->family) { case AF_INET: r = sd_netlink_message_read_in_addr(message, IFA_LOCAL, &tmp->in_addr.in); @@ -1561,19 +1544,6 @@ int manager_rtnl_process_address(sd_netlink *rtnl, sd_netlink_message *message, tmp->in_addr_peer = IN_ADDR_NULL; } - r = sd_netlink_message_read_in_addr(message, IFA_BROADCAST, &tmp->broadcast); - if (r < 0 && r != -ENODATA) { - log_link_warning_errno(link, r, "rtnl: could not get broadcast from address message, ignoring: %m"); - return 0; - } - - r = sd_netlink_message_read_string_strdup(message, IFA_LABEL, &tmp->label); - if (r < 0 && r != -ENODATA) { - log_link_warning_errno(link, r, "rtnl: could not get label from address message, ignoring: %m"); - return 0; - } else if (r >= 0 && streq_ptr(tmp->label, link->ifname)) - tmp->label = mfree(tmp->label); - break; case AF_INET6: @@ -1603,52 +1573,10 @@ int manager_rtnl_process_address(sd_netlink *rtnl, sd_netlink_message *message, assert_not_reached(); } - r = sd_netlink_message_read_cache_info(message, IFA_CACHEINFO, &cinfo); - if (r < 0 && r != -ENODATA) { - log_link_warning_errno(link, r, "rtnl: cannot get IFA_CACHEINFO attribute, ignoring: %m"); - return 0; - } - + /* Then, find the managed Address object corresponding to the received address. */ (void) address_get(link, tmp, &address); - switch (type) { - case RTM_NEWADDR: - if (address) { - /* update flags and etc. */ - r = address_equalify(address, tmp); - if (r < 0) { - log_link_warning_errno(link, r, "Failed to update properties of address %s, ignoring: %m", - IN_ADDR_PREFIX_TO_STRING(address->family, &address->in_addr, address->prefixlen)); - return 0; - } - address->flags = tmp->flags; - address->scope = tmp->scope; - address_set_lifetime(m, address, &cinfo); - address_enter_configured(address); - log_address_debug(address, "Received updated", link); - } else { - address_set_lifetime(m, tmp, &cinfo); - address_enter_configured(tmp); - log_address_debug(tmp, "Received new", link); - - r = address_add(link, tmp); - if (r < 0) { - log_link_warning_errno(link, r, "Failed to remember foreign address %s, ignoring: %m", - IN_ADDR_PREFIX_TO_STRING(tmp->family, &tmp->in_addr, tmp->prefixlen)); - return 0; - } - - address = TAKE_PTR(tmp); - } - - /* address_update() logs internally, so we don't need to here. */ - r = address_update(address); - if (r < 0) - link_enter_failed(link); - - break; - - case RTM_DELADDR: + if (type == RTM_DELADDR) { if (address) { address_enter_removed(address); log_address_debug(address, address->state == 0 ? "Forgetting" : "Removed", link); @@ -1656,12 +1584,72 @@ int manager_rtnl_process_address(sd_netlink *rtnl, sd_netlink_message *message, } else log_address_debug(tmp, "Kernel removed unknown", link); - break; - - default: - assert_not_reached(); + return 0; } + if (!address) { + /* If we did not know the address, then save it. */ + r = address_add(link, tmp); + if (r < 0) { + log_link_warning_errno(link, r, "Failed to remember foreign address %s, ignoring: %m", + IN_ADDR_PREFIX_TO_STRING(tmp->family, &tmp->in_addr, tmp->prefixlen)); + return 0; + } + address = TAKE_PTR(tmp); + + is_new = true; + + } else { + /* Otherwise, update the managed Address object with the netlink notification. */ + address->prefixlen = tmp->prefixlen; + address->in_addr_peer = tmp->in_addr_peer; + } + + /* Then, update miscellaneous info. */ + r = sd_rtnl_message_addr_get_scope(message, &address->scope); + if (r < 0) + log_link_debug_errno(link, r, "rtnl: received address message without scope, ignoring: %m"); + + if (address->family == AF_INET) { + _cleanup_free_ char *label = NULL; + + r = sd_netlink_message_read_string_strdup(message, IFA_LABEL, &label); + if (r >= 0) { + if (!streq_ptr(label, link->ifname)) + free_and_replace(address->label, label); + } else if (r != -ENODATA) + log_link_debug_errno(link, r, "rtnl: could not get label from address message, ignoring: %m"); + + r = sd_netlink_message_read_in_addr(message, IFA_BROADCAST, &address->broadcast); + if (r < 0 && r != -ENODATA) + log_link_debug_errno(link, r, "rtnl: could not get broadcast from address message, ignoring: %m"); + } + + r = sd_netlink_message_read_u32(message, IFA_FLAGS, &address->flags); + if (r == -ENODATA) { + unsigned char flags; + + /* For old kernels. */ + r = sd_rtnl_message_addr_get_flags(message, &flags); + if (r >= 0) + address->flags = flags; + } else if (r < 0) + log_link_debug_errno(link, r, "rtnl: failed to read IFA_FLAGS attribute, ignoring: %m"); + + r = sd_netlink_message_read_cache_info(message, IFA_CACHEINFO, &cinfo); + if (r >= 0) + address_set_lifetime(m, address, &cinfo); + else if (r != -ENODATA) + log_link_debug_errno(link, r, "rtnl: failed to read IFA_CACHEINFO attribute, ignoring: %m"); + + address_enter_configured(address); + log_address_debug(address, is_new ? "Received new": "Received updated", link); + + /* address_update() logs internally, so we don't need to here. */ + r = address_update(address); + if (r < 0) + link_enter_failed(link); + return 1; } From 0a0c2672dbd22dc85d660e5baa7e1bef701beb88 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sun, 9 Jul 2023 08:42:25 +0900 Subject: [PATCH 2/5] network/address: do not add Address object to Link on requesting Then, all addresses managed by a link really exist (unless the kernel silently removes addresses). By this change, now Address objects managed by Link and owned by Request are decoupled, and always requested settings will be applied. Fixes #25843. --- src/network/networkd-address.c | 168 +++++++++++++++++++-------------- 1 file changed, 98 insertions(+), 70 deletions(-) diff --git a/src/network/networkd-address.c b/src/network/networkd-address.c index e9959486a7..f2a88da411 100644 --- a/src/network/networkd-address.c +++ b/src/network/networkd-address.c @@ -457,43 +457,6 @@ int address_equal(const Address *a1, const Address *a2) { return address_compare_func(a1, a2) == 0; } -static int address_equalify(Address *address, const Address *src) { - bool src_is_null; - int r; - - assert(address); - assert(src); - - src_is_null = address_is_static_null(src); - - if (src_is_null) { - /* When the source address has an null address, then we cannot compare the two objects with - * address_kernel_compare_func(). Let's do minimal check here. */ - if (address->family != src->family) - return -EINVAL; - if (address->prefixlen != src->prefixlen) - return -EINVAL; - - } else if (address_kernel_compare_func(address, src) != 0) - return -EINVAL; - - if (address->family == AF_INET) { - /* When the source is null, then the broadcast address will be determined based on the - * acquired address. Hence, do not copy it here. */ - if (!src_is_null) - address->broadcast = src->broadcast; - - r = free_and_strdup(&address->label, src->label); - if (r < 0) - return r; - } else { - address->prefixlen = src->prefixlen; - address->in_addr_peer = src->in_addr_peer; - } - - return 0; -} - int address_dup(const Address *src, Address **ret) { _cleanup_(address_freep) Address *dest = NULL; int r; @@ -626,8 +589,7 @@ static int address_drop(Address *address) { address_del_netlabel(address); - if (address->state == 0) - address_free(address); + address_free(address); link_update_operstate(link, /* also_update_master = */ true); link_check_ready(link); @@ -655,6 +617,47 @@ static bool address_match_null(const Address *a, const Address *null_address) { return true; } +static int address_get_request(Link *link, const Address *address, Request **ret) { + Request *req; + + assert(link); + assert(link->manager); + assert(address); + + req = ordered_set_get( + link->manager->request_queue, + &(Request) { + .link = link, + .type = REQUEST_TYPE_ADDRESS, + .userdata = (void*) address, + .hash_func = (hash_func_t) address_kernel_hash_func, + .compare_func = (compare_func_t) address_kernel_compare_func, + }); + if (req) { + if (ret) + *ret = req; + return 0; + } + + if (address_is_static_null(address)) + ORDERED_SET_FOREACH(req, link->manager->request_queue) { + if (req->link != link) + continue; + if (req->type != REQUEST_TYPE_ADDRESS) + continue; + + if (!address_match_null(req->userdata, address)) + continue; + + if (ret) + *ret = req; + + return 0; + } + + return -ENOENT; +} + int address_get(Link *link, const Address *in, Address **ret) { Address *a; @@ -874,6 +877,7 @@ static int address_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, Link int address_remove(Address *address) { _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; + Request *req; Link *link; int r; @@ -906,6 +910,8 @@ int address_remove(Address *address) { link_ref(link); address_enter_removing(address); + if (address_get_request(link, address, &req) >= 0) + address_enter_removing(req->userdata); /* The operational state is determined by address state and carrier state. Hence, if we remove * an address, the operational state may be changed. */ @@ -1275,6 +1281,7 @@ static bool address_is_ready_to_configure(Link *link, const Address *address) { } static int address_process_request(Request *req, Link *link, Address *address) { + struct Address *existing; struct ifa_cacheinfo c; int r; @@ -1290,7 +1297,10 @@ static int address_process_request(Request *req, Link *link, Address *address) { log_link_debug(link, "Refuse to configure %s address %s, as its valid lifetime is zero.", network_config_source_to_string(address->source), IN_ADDR_PREFIX_TO_STRING(address->family, &address->in_addr, address->prefixlen)); + address_cancel_requesting(address); + if (address_get(link, address, &existing) >= 0) + address_enter_configuring(existing); return 1; } @@ -1299,6 +1309,9 @@ static int address_process_request(Request *req, Link *link, Address *address) { return log_link_warning_errno(link, r, "Failed to configure address: %m"); address_enter_configuring(address); + if (address_get(link, address, &existing) >= 0) + address_enter_configuring(existing); + return 1; } @@ -1309,59 +1322,52 @@ int link_request_address( address_netlink_handler_t netlink_handler, Request **ret) { - Address *existing; + _cleanup_(address_freep) Address *tmp = NULL; + Address *existing = NULL; int r; assert(link); assert(address); assert(address->source != NETWORK_CONFIG_SOURCE_FOREIGN); - if (address_get(link, address, &existing) < 0) { - _cleanup_(address_freep) Address *tmp = NULL; + if (address->lifetime_valid_usec == 0) + /* The requested address is outdated. Let's ignore the request. */ + return 0; - if (address->lifetime_valid_usec == 0) - /* The requested address is outdated. Let's ignore the request. */ - return 0; + if (address_get(link, address, &existing) < 0) { + if (address_get_request(link, address, NULL) >= 0) + return 0; /* already requested, skipping. */ r = address_acquire(link, address, &tmp); if (r < 0) return log_link_warning_errno(link, r, "Failed to acquire an address from pool: %m"); - address_set_broadcast(tmp, link); - /* Consider address tentative until we get the real flags from the kernel */ tmp->flags |= IFA_F_TENTATIVE; - r = address_add(link, tmp); - if (r < 0) - return log_link_warning_errno(link, r, "Failed to save requested address: %m"); - - existing = TAKE_PTR(tmp); } else { - if (address->lifetime_valid_usec == 0) - /* The requested address is outdated. Let's remove it. */ - return address_remove_and_drop(existing); - - r = address_equalify(existing, address); + r = address_dup(address, &tmp); if (r < 0) - return log_link_warning_errno(link, r, "Failed to equalify saved address with the requested one: %m"); + return log_oom(); - address_set_broadcast(existing, link); + /* Copy already assigned address when it is requested as a null address. */ + if (address_is_static_null(address)) + tmp->in_addr = existing->in_addr; - existing->source = address->source; - existing->provider = address->provider; - existing->duplicate_address_detection = address->duplicate_address_detection; - existing->lifetime_valid_usec = address->lifetime_valid_usec; - existing->lifetime_preferred_usec = address->lifetime_preferred_usec; + /* Copy state for logging below. */ + tmp->state = existing->state; } - r = ipv4acd_configure(link, existing); + address_set_broadcast(tmp, link); + + r = ipv4acd_configure(link, tmp); if (r < 0) return r; - log_address_debug(existing, "Requesting", link); + log_address_debug(tmp, "Requesting", link); r = link_queue_request_safe(link, REQUEST_TYPE_ADDRESS, - existing, NULL, + tmp, + address_free, address_kernel_hash_func, address_kernel_compare_func, address_process_request, @@ -1371,8 +1377,11 @@ int link_request_address( if (r == 0) return 0; - address_enter_requesting(existing); + address_enter_requesting(tmp); + if (existing) + address_enter_requesting(existing); + TAKE_PTR(tmp); return 1; } @@ -1464,6 +1473,7 @@ int manager_rtnl_process_address(sd_netlink *rtnl, sd_netlink_message *message, Link *link; uint16_t type; Address *address = NULL; + Request *req = NULL; bool is_new = false; int ifindex, r; @@ -1573,17 +1583,21 @@ int manager_rtnl_process_address(sd_netlink *rtnl, sd_netlink_message *message, assert_not_reached(); } - /* Then, find the managed Address object corresponding to the received address. */ + /* Then, find the managed Address and Request objects corresponding to the received address. */ (void) address_get(link, tmp, &address); + (void) address_get_request(link, tmp, &req); if (type == RTM_DELADDR) { if (address) { address_enter_removed(address); - log_address_debug(address, address->state == 0 ? "Forgetting" : "Removed", link); + log_address_debug(address, "Forgetting removed", link); (void) address_drop(address); } else log_address_debug(tmp, "Kernel removed unknown", link); + if (req) + address_enter_removed(req->userdata); + return 0; } @@ -1605,6 +1619,17 @@ int manager_rtnl_process_address(sd_netlink *rtnl, sd_netlink_message *message, address->in_addr_peer = tmp->in_addr_peer; } + /* Also update information that cannot be obtained through netlink notification. */ + if (req && req->waiting_reply) { + Address *a = ASSERT_PTR(req->userdata); + + address->source = a->source; + address->provider = a->provider; + (void) free_and_strdup_warn(&address->netlabel, a->netlabel); + address->requested_as_null = a->requested_as_null; + address->callback = a->callback; + } + /* Then, update miscellaneous info. */ r = sd_rtnl_message_addr_get_scope(message, &address->scope); if (r < 0) @@ -1643,6 +1668,9 @@ int manager_rtnl_process_address(sd_netlink *rtnl, sd_netlink_message *message, log_link_debug_errno(link, r, "rtnl: failed to read IFA_CACHEINFO attribute, ignoring: %m"); address_enter_configured(address); + if (req) + address_enter_configured(req->userdata); + log_address_debug(address, is_new ? "Received new": "Received updated", link); /* address_update() logs internally, so we don't need to here. */ From b33dd04ebe40683e142e303a8a166273eaf56db5 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Tue, 11 Jul 2023 12:11:18 +0900 Subject: [PATCH 3/5] network/address: introduce address_get_harder() and use it where appropriate With the previous change, now Address objects under requesting are not owned by Link object, hence we need to also search corresponding Address object in the request queue. --- src/network/networkd-address.c | 20 +++++++++++++++++++ src/network/networkd-address.h | 1 + src/network/networkd-dhcp-prefix-delegation.c | 2 +- src/network/networkd-dhcp-server.c | 4 ++-- src/network/networkd-dhcp6.c | 2 +- 5 files changed, 25 insertions(+), 4 deletions(-) diff --git a/src/network/networkd-address.c b/src/network/networkd-address.c index f2a88da411..2dd02f5efb 100644 --- a/src/network/networkd-address.c +++ b/src/network/networkd-address.c @@ -685,6 +685,26 @@ int address_get(Link *link, const Address *in, Address **ret) { return -ENOENT; } +int address_get_harder(Link *link, const Address *in, Address **ret) { + Request *req; + int r; + + assert(link); + assert(in); + + if (address_get(link, in, ret) >= 0) + return 0; + + r = address_get_request(link, in, &req); + if (r < 0) + return r; + + if (ret) + *ret = ASSERT_PTR(req->userdata); + + return 0; +} + int link_get_address(Link *link, int family, const union in_addr_union *address, unsigned char prefixlen, Address **ret) { Address *a; int r; diff --git a/src/network/networkd-address.h b/src/network/networkd-address.h index 9b418af414..bdb5b5b5e5 100644 --- a/src/network/networkd-address.h +++ b/src/network/networkd-address.h @@ -73,6 +73,7 @@ int address_flags_to_string_alloc(uint32_t flags, int family, char **ret); int address_new(Address **ret); Address* address_free(Address *address); int address_get(Link *link, const Address *in, Address **ret); +int address_get_harder(Link *link, const Address *in, Address **ret); int address_configure_handler_internal(sd_netlink *rtnl, sd_netlink_message *m, Link *link, const char *error_msg); int address_remove(Address *address); int address_remove_and_drop(Address *address); diff --git a/src/network/networkd-dhcp-prefix-delegation.c b/src/network/networkd-dhcp-prefix-delegation.c index 8d50da042c..169f1b3b5e 100644 --- a/src/network/networkd-dhcp-prefix-delegation.c +++ b/src/network/networkd-dhcp-prefix-delegation.c @@ -359,7 +359,7 @@ static void log_dhcp_pd_address(Link *link, const Address *address) { assert(address); assert(address->family == AF_INET6); - int log_level = address_get(link, address, NULL) >= 0 ? LOG_DEBUG : LOG_INFO; + int log_level = address_get_harder(link, address, NULL) >= 0 ? LOG_DEBUG : LOG_INFO; if (log_level < log_get_max_level()) return; diff --git a/src/network/networkd-dhcp-server.c b/src/network/networkd-dhcp-server.c index 50d84893c6..8221fd92db 100644 --- a/src/network/networkd-dhcp-server.c +++ b/src/network/networkd-dhcp-server.c @@ -108,8 +108,8 @@ int link_request_dhcp_server_address(Link *link) { address->prefixlen = link->network->dhcp_server_address_prefixlen; address_set_broadcast(address, link); - if (address_get(link, address, &existing) >= 0 && - address_exists(existing) && + if (address_get_harder(link, address, &existing) >= 0 && + (address_exists(existing) || address_is_requesting(existing)) && existing->source == NETWORK_CONFIG_SOURCE_STATIC) /* The same address seems explicitly configured in [Address] or [Network] section. * Configure the DHCP server address only when it is not. */ diff --git a/src/network/networkd-dhcp6.c b/src/network/networkd-dhcp6.c index 755957f5b1..00c767e1fb 100644 --- a/src/network/networkd-dhcp6.c +++ b/src/network/networkd-dhcp6.c @@ -161,7 +161,7 @@ static int verify_dhcp6_address(Link *link, const Address *address) { const char *pretty = IN6_ADDR_TO_STRING(&address->in_addr.in6); - if (address_get(link, address, &existing) < 0) { + if (address_get_harder(link, address, &existing) < 0) { /* New address. */ log_level = LOG_INFO; goto simple_log; From 7e18f9b48711e74232555d595dbd50d9bd96e088 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sun, 9 Jul 2023 12:36:34 +0900 Subject: [PATCH 4/5] network/address: also save/update priority of prefix route Strictly speaking, this is not necessary, but let's make the managed Address objects more consistent with the kernel's addresses. --- src/network/networkd-address.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/network/networkd-address.c b/src/network/networkd-address.c index 2dd02f5efb..e49d21f804 100644 --- a/src/network/networkd-address.c +++ b/src/network/networkd-address.c @@ -1687,6 +1687,10 @@ int manager_rtnl_process_address(sd_netlink *rtnl, sd_netlink_message *message, else if (r != -ENODATA) log_link_debug_errno(link, r, "rtnl: failed to read IFA_CACHEINFO attribute, ignoring: %m"); + r = sd_netlink_message_read_u32(message, IFA_RT_PRIORITY, &address->route_metric); + if (r < 0 && r != -ENODATA) + log_link_debug_errno(link, r, "rtnl: failed to read IFA_RT_PRIORITY attribute, ignoring: %m"); + address_enter_configured(address); if (req) address_enter_configured(req->userdata); From d19704cd21c5151b2e0c06ae4a0cdf4cacf81bb0 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sun, 9 Jul 2023 09:54:25 +0900 Subject: [PATCH 5/5] test-network: add testcase for overriding Address.RouteMetric= For issue #25843. --- .../conf/25-address-static.network | 261 +----------------- .../10-many-address.conf | 258 +++++++++++++++++ .../10-override-route-metric.conf | 9 + test/test-network/systemd-networkd-tests.py | 75 +++-- 4 files changed, 321 insertions(+), 282 deletions(-) create mode 100644 test/test-network/conf/25-address-static.network.d/10-many-address.conf create mode 100644 test/test-network/conf/25-address-static.network.d/10-override-route-metric.conf diff --git a/test/test-network/conf/25-address-static.network b/test/test-network/conf/25-address-static.network index 6d2baa3972..2a96491b52 100644 --- a/test/test-network/conf/25-address-static.network +++ b/test/test-network/conf/25-address-static.network @@ -55,6 +55,10 @@ Address=2001:db8:0:f102::16/64 Address=2001:db8:0:f103::20/128 Peer=2001:db8:0:f103::10/128 +[Address] +Address=2001:db8:0:f104::16/64 +RouteMetric=128 + [Address] Address=::/64 @@ -105,263 +109,6 @@ RouteMetric=128 Address=10.9.0.1/16 RouteMetric=hoge -# test for ENOBUFS issue #17012 -[Network] -Address=10.3.3.1/16 -Address=10.3.3.2/16 -Address=10.3.3.3/16 -Address=10.3.3.4/16 -Address=10.3.3.5/16 -Address=10.3.3.6/16 -Address=10.3.3.7/16 -Address=10.3.3.8/16 -Address=10.3.3.9/16 -Address=10.3.3.10/16 -Address=10.3.3.11/16 -Address=10.3.3.12/16 -Address=10.3.3.13/16 -Address=10.3.3.14/16 -Address=10.3.3.15/16 -Address=10.3.3.16/16 -Address=10.3.3.17/16 -Address=10.3.3.18/16 -Address=10.3.3.19/16 -Address=10.3.3.20/16 -Address=10.3.3.21/16 -Address=10.3.3.22/16 -Address=10.3.3.23/16 -Address=10.3.3.24/16 -Address=10.3.3.25/16 -Address=10.3.3.26/16 -Address=10.3.3.27/16 -Address=10.3.3.28/16 -Address=10.3.3.29/16 -Address=10.3.3.30/16 -Address=10.3.3.31/16 -Address=10.3.3.32/16 -Address=10.3.3.33/16 -Address=10.3.3.34/16 -Address=10.3.3.35/16 -Address=10.3.3.36/16 -Address=10.3.3.37/16 -Address=10.3.3.38/16 -Address=10.3.3.39/16 -Address=10.3.3.40/16 -Address=10.3.3.41/16 -Address=10.3.3.42/16 -Address=10.3.3.43/16 -Address=10.3.3.44/16 -Address=10.3.3.45/16 -Address=10.3.3.46/16 -Address=10.3.3.47/16 -Address=10.3.3.48/16 -Address=10.3.3.49/16 -Address=10.3.3.50/16 -Address=10.3.3.51/16 -Address=10.3.3.52/16 -Address=10.3.3.53/16 -Address=10.3.3.54/16 -Address=10.3.3.55/16 -Address=10.3.3.56/16 -Address=10.3.3.57/16 -Address=10.3.3.58/16 -Address=10.3.3.59/16 -Address=10.3.3.60/16 -Address=10.3.3.61/16 -Address=10.3.3.62/16 -Address=10.3.3.63/16 -Address=10.3.3.64/16 -Address=10.3.3.65/16 -Address=10.3.3.66/16 -Address=10.3.3.67/16 -Address=10.3.3.68/16 -Address=10.3.3.69/16 -Address=10.3.3.70/16 -Address=10.3.3.71/16 -Address=10.3.3.72/16 -Address=10.3.3.73/16 -Address=10.3.3.74/16 -Address=10.3.3.75/16 -Address=10.3.3.76/16 -Address=10.3.3.77/16 -Address=10.3.3.78/16 -Address=10.3.3.79/16 -Address=10.3.3.80/16 -Address=10.3.3.81/16 -Address=10.3.3.82/16 -Address=10.3.3.83/16 -Address=10.3.3.84/16 -Address=10.3.3.85/16 -Address=10.3.3.86/16 -Address=10.3.3.87/16 -Address=10.3.3.88/16 -Address=10.3.3.89/16 -Address=10.3.3.90/16 -Address=10.3.3.91/16 -Address=10.3.3.92/16 -Address=10.3.3.93/16 -Address=10.3.3.94/16 -Address=10.3.3.95/16 -Address=10.3.3.96/16 -Address=10.3.3.97/16 -Address=10.3.3.98/16 -Address=10.3.3.99/16 -Address=10.3.3.100/16 -Address=10.3.3.101/16 -Address=10.3.3.102/16 -Address=10.3.3.103/16 -Address=10.3.3.104/16 -Address=10.3.3.105/16 -Address=10.3.3.106/16 -Address=10.3.3.107/16 -Address=10.3.3.108/16 -Address=10.3.3.109/16 -Address=10.3.3.110/16 -Address=10.3.3.111/16 -Address=10.3.3.112/16 -Address=10.3.3.113/16 -Address=10.3.3.114/16 -Address=10.3.3.115/16 -Address=10.3.3.116/16 -Address=10.3.3.117/16 -Address=10.3.3.118/16 -Address=10.3.3.119/16 -Address=10.3.3.120/16 -Address=10.3.3.121/16 -Address=10.3.3.122/16 -Address=10.3.3.123/16 -Address=10.3.3.124/16 -Address=10.3.3.125/16 -Address=10.3.3.126/16 -Address=10.3.3.127/16 -Address=10.3.3.128/16 -Address=10.3.3.129/16 -Address=10.3.3.130/16 -Address=10.3.3.131/16 -Address=10.3.3.132/16 -Address=10.3.3.133/16 -Address=10.3.3.134/16 -Address=10.3.3.135/16 -Address=10.3.3.136/16 -Address=10.3.3.137/16 -Address=10.3.3.138/16 -Address=10.3.3.139/16 -Address=10.3.3.140/16 -Address=10.3.3.141/16 -Address=10.3.3.142/16 -Address=10.3.3.143/16 -Address=10.3.3.144/16 -Address=10.3.3.145/16 -Address=10.3.3.146/16 -Address=10.3.3.147/16 -Address=10.3.3.148/16 -Address=10.3.3.149/16 -Address=10.3.3.150/16 -Address=10.3.3.151/16 -Address=10.3.3.152/16 -Address=10.3.3.153/16 -Address=10.3.3.154/16 -Address=10.3.3.155/16 -Address=10.3.3.156/16 -Address=10.3.3.157/16 -Address=10.3.3.158/16 -Address=10.3.3.159/16 -Address=10.3.3.160/16 -Address=10.3.3.161/16 -Address=10.3.3.162/16 -Address=10.3.3.163/16 -Address=10.3.3.164/16 -Address=10.3.3.165/16 -Address=10.3.3.166/16 -Address=10.3.3.167/16 -Address=10.3.3.168/16 -Address=10.3.3.169/16 -Address=10.3.3.170/16 -Address=10.3.3.171/16 -Address=10.3.3.172/16 -Address=10.3.3.173/16 -Address=10.3.3.174/16 -Address=10.3.3.175/16 -Address=10.3.3.176/16 -Address=10.3.3.177/16 -Address=10.3.3.178/16 -Address=10.3.3.179/16 -Address=10.3.3.180/16 -Address=10.3.3.181/16 -Address=10.3.3.182/16 -Address=10.3.3.183/16 -Address=10.3.3.184/16 -Address=10.3.3.185/16 -Address=10.3.3.186/16 -Address=10.3.3.187/16 -Address=10.3.3.188/16 -Address=10.3.3.189/16 -Address=10.3.3.190/16 -Address=10.3.3.191/16 -Address=10.3.3.192/16 -Address=10.3.3.193/16 -Address=10.3.3.194/16 -Address=10.3.3.195/16 -Address=10.3.3.196/16 -Address=10.3.3.197/16 -Address=10.3.3.198/16 -Address=10.3.3.199/16 -Address=10.3.3.200/16 -Address=10.3.3.201/16 -Address=10.3.3.202/16 -Address=10.3.3.203/16 -Address=10.3.3.204/16 -Address=10.3.3.205/16 -Address=10.3.3.206/16 -Address=10.3.3.207/16 -Address=10.3.3.208/16 -Address=10.3.3.209/16 -Address=10.3.3.210/16 -Address=10.3.3.211/16 -Address=10.3.3.212/16 -Address=10.3.3.213/16 -Address=10.3.3.214/16 -Address=10.3.3.215/16 -Address=10.3.3.216/16 -Address=10.3.3.217/16 -Address=10.3.3.218/16 -Address=10.3.3.219/16 -Address=10.3.3.220/16 -Address=10.3.3.221/16 -Address=10.3.3.222/16 -Address=10.3.3.223/16 -Address=10.3.3.224/16 -Address=10.3.3.225/16 -Address=10.3.3.226/16 -Address=10.3.3.227/16 -Address=10.3.3.228/16 -Address=10.3.3.229/16 -Address=10.3.3.230/16 -Address=10.3.3.231/16 -Address=10.3.3.232/16 -Address=10.3.3.233/16 -Address=10.3.3.234/16 -Address=10.3.3.235/16 -Address=10.3.3.236/16 -Address=10.3.3.237/16 -Address=10.3.3.238/16 -Address=10.3.3.239/16 -Address=10.3.3.240/16 -Address=10.3.3.241/16 -Address=10.3.3.242/16 -Address=10.3.3.243/16 -Address=10.3.3.244/16 -Address=10.3.3.245/16 -Address=10.3.3.246/16 -Address=10.3.3.247/16 -Address=10.3.3.248/16 -Address=10.3.3.249/16 -Address=10.3.3.250/16 -Address=10.3.3.251/16 -Address=10.3.3.252/16 -Address=10.3.3.253/16 -Address=10.3.3.254/16 - [Address] Address=10.4.3.2/24 # just a random label which should exist diff --git a/test/test-network/conf/25-address-static.network.d/10-many-address.conf b/test/test-network/conf/25-address-static.network.d/10-many-address.conf new file mode 100644 index 0000000000..73c64c6ae8 --- /dev/null +++ b/test/test-network/conf/25-address-static.network.d/10-many-address.conf @@ -0,0 +1,258 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later + +[Network] +# test for ENOBUFS issue #17012 +Address=10.3.3.1/16 +Address=10.3.3.2/16 +Address=10.3.3.3/16 +Address=10.3.3.4/16 +Address=10.3.3.5/16 +Address=10.3.3.6/16 +Address=10.3.3.7/16 +Address=10.3.3.8/16 +Address=10.3.3.9/16 +Address=10.3.3.10/16 +Address=10.3.3.11/16 +Address=10.3.3.12/16 +Address=10.3.3.13/16 +Address=10.3.3.14/16 +Address=10.3.3.15/16 +Address=10.3.3.16/16 +Address=10.3.3.17/16 +Address=10.3.3.18/16 +Address=10.3.3.19/16 +Address=10.3.3.20/16 +Address=10.3.3.21/16 +Address=10.3.3.22/16 +Address=10.3.3.23/16 +Address=10.3.3.24/16 +Address=10.3.3.25/16 +Address=10.3.3.26/16 +Address=10.3.3.27/16 +Address=10.3.3.28/16 +Address=10.3.3.29/16 +Address=10.3.3.30/16 +Address=10.3.3.31/16 +Address=10.3.3.32/16 +Address=10.3.3.33/16 +Address=10.3.3.34/16 +Address=10.3.3.35/16 +Address=10.3.3.36/16 +Address=10.3.3.37/16 +Address=10.3.3.38/16 +Address=10.3.3.39/16 +Address=10.3.3.40/16 +Address=10.3.3.41/16 +Address=10.3.3.42/16 +Address=10.3.3.43/16 +Address=10.3.3.44/16 +Address=10.3.3.45/16 +Address=10.3.3.46/16 +Address=10.3.3.47/16 +Address=10.3.3.48/16 +Address=10.3.3.49/16 +Address=10.3.3.50/16 +Address=10.3.3.51/16 +Address=10.3.3.52/16 +Address=10.3.3.53/16 +Address=10.3.3.54/16 +Address=10.3.3.55/16 +Address=10.3.3.56/16 +Address=10.3.3.57/16 +Address=10.3.3.58/16 +Address=10.3.3.59/16 +Address=10.3.3.60/16 +Address=10.3.3.61/16 +Address=10.3.3.62/16 +Address=10.3.3.63/16 +Address=10.3.3.64/16 +Address=10.3.3.65/16 +Address=10.3.3.66/16 +Address=10.3.3.67/16 +Address=10.3.3.68/16 +Address=10.3.3.69/16 +Address=10.3.3.70/16 +Address=10.3.3.71/16 +Address=10.3.3.72/16 +Address=10.3.3.73/16 +Address=10.3.3.74/16 +Address=10.3.3.75/16 +Address=10.3.3.76/16 +Address=10.3.3.77/16 +Address=10.3.3.78/16 +Address=10.3.3.79/16 +Address=10.3.3.80/16 +Address=10.3.3.81/16 +Address=10.3.3.82/16 +Address=10.3.3.83/16 +Address=10.3.3.84/16 +Address=10.3.3.85/16 +Address=10.3.3.86/16 +Address=10.3.3.87/16 +Address=10.3.3.88/16 +Address=10.3.3.89/16 +Address=10.3.3.90/16 +Address=10.3.3.91/16 +Address=10.3.3.92/16 +Address=10.3.3.93/16 +Address=10.3.3.94/16 +Address=10.3.3.95/16 +Address=10.3.3.96/16 +Address=10.3.3.97/16 +Address=10.3.3.98/16 +Address=10.3.3.99/16 +Address=10.3.3.100/16 +Address=10.3.3.101/16 +Address=10.3.3.102/16 +Address=10.3.3.103/16 +Address=10.3.3.104/16 +Address=10.3.3.105/16 +Address=10.3.3.106/16 +Address=10.3.3.107/16 +Address=10.3.3.108/16 +Address=10.3.3.109/16 +Address=10.3.3.110/16 +Address=10.3.3.111/16 +Address=10.3.3.112/16 +Address=10.3.3.113/16 +Address=10.3.3.114/16 +Address=10.3.3.115/16 +Address=10.3.3.116/16 +Address=10.3.3.117/16 +Address=10.3.3.118/16 +Address=10.3.3.119/16 +Address=10.3.3.120/16 +Address=10.3.3.121/16 +Address=10.3.3.122/16 +Address=10.3.3.123/16 +Address=10.3.3.124/16 +Address=10.3.3.125/16 +Address=10.3.3.126/16 +Address=10.3.3.127/16 +Address=10.3.3.128/16 +Address=10.3.3.129/16 +Address=10.3.3.130/16 +Address=10.3.3.131/16 +Address=10.3.3.132/16 +Address=10.3.3.133/16 +Address=10.3.3.134/16 +Address=10.3.3.135/16 +Address=10.3.3.136/16 +Address=10.3.3.137/16 +Address=10.3.3.138/16 +Address=10.3.3.139/16 +Address=10.3.3.140/16 +Address=10.3.3.141/16 +Address=10.3.3.142/16 +Address=10.3.3.143/16 +Address=10.3.3.144/16 +Address=10.3.3.145/16 +Address=10.3.3.146/16 +Address=10.3.3.147/16 +Address=10.3.3.148/16 +Address=10.3.3.149/16 +Address=10.3.3.150/16 +Address=10.3.3.151/16 +Address=10.3.3.152/16 +Address=10.3.3.153/16 +Address=10.3.3.154/16 +Address=10.3.3.155/16 +Address=10.3.3.156/16 +Address=10.3.3.157/16 +Address=10.3.3.158/16 +Address=10.3.3.159/16 +Address=10.3.3.160/16 +Address=10.3.3.161/16 +Address=10.3.3.162/16 +Address=10.3.3.163/16 +Address=10.3.3.164/16 +Address=10.3.3.165/16 +Address=10.3.3.166/16 +Address=10.3.3.167/16 +Address=10.3.3.168/16 +Address=10.3.3.169/16 +Address=10.3.3.170/16 +Address=10.3.3.171/16 +Address=10.3.3.172/16 +Address=10.3.3.173/16 +Address=10.3.3.174/16 +Address=10.3.3.175/16 +Address=10.3.3.176/16 +Address=10.3.3.177/16 +Address=10.3.3.178/16 +Address=10.3.3.179/16 +Address=10.3.3.180/16 +Address=10.3.3.181/16 +Address=10.3.3.182/16 +Address=10.3.3.183/16 +Address=10.3.3.184/16 +Address=10.3.3.185/16 +Address=10.3.3.186/16 +Address=10.3.3.187/16 +Address=10.3.3.188/16 +Address=10.3.3.189/16 +Address=10.3.3.190/16 +Address=10.3.3.191/16 +Address=10.3.3.192/16 +Address=10.3.3.193/16 +Address=10.3.3.194/16 +Address=10.3.3.195/16 +Address=10.3.3.196/16 +Address=10.3.3.197/16 +Address=10.3.3.198/16 +Address=10.3.3.199/16 +Address=10.3.3.200/16 +Address=10.3.3.201/16 +Address=10.3.3.202/16 +Address=10.3.3.203/16 +Address=10.3.3.204/16 +Address=10.3.3.205/16 +Address=10.3.3.206/16 +Address=10.3.3.207/16 +Address=10.3.3.208/16 +Address=10.3.3.209/16 +Address=10.3.3.210/16 +Address=10.3.3.211/16 +Address=10.3.3.212/16 +Address=10.3.3.213/16 +Address=10.3.3.214/16 +Address=10.3.3.215/16 +Address=10.3.3.216/16 +Address=10.3.3.217/16 +Address=10.3.3.218/16 +Address=10.3.3.219/16 +Address=10.3.3.220/16 +Address=10.3.3.221/16 +Address=10.3.3.222/16 +Address=10.3.3.223/16 +Address=10.3.3.224/16 +Address=10.3.3.225/16 +Address=10.3.3.226/16 +Address=10.3.3.227/16 +Address=10.3.3.228/16 +Address=10.3.3.229/16 +Address=10.3.3.230/16 +Address=10.3.3.231/16 +Address=10.3.3.232/16 +Address=10.3.3.233/16 +Address=10.3.3.234/16 +Address=10.3.3.235/16 +Address=10.3.3.236/16 +Address=10.3.3.237/16 +Address=10.3.3.238/16 +Address=10.3.3.239/16 +Address=10.3.3.240/16 +Address=10.3.3.241/16 +Address=10.3.3.242/16 +Address=10.3.3.243/16 +Address=10.3.3.244/16 +Address=10.3.3.245/16 +Address=10.3.3.246/16 +Address=10.3.3.247/16 +Address=10.3.3.248/16 +Address=10.3.3.249/16 +Address=10.3.3.250/16 +Address=10.3.3.251/16 +Address=10.3.3.252/16 +Address=10.3.3.253/16 +Address=10.3.3.254/16 diff --git a/test/test-network/conf/25-address-static.network.d/10-override-route-metric.conf b/test/test-network/conf/25-address-static.network.d/10-override-route-metric.conf new file mode 100644 index 0000000000..da5bec2a34 --- /dev/null +++ b/test/test-network/conf/25-address-static.network.d/10-override-route-metric.conf @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later + +[Address] +Address=10.9.0.1/16 +RouteMetric=256 + +[Address] +Address=2001:db8:0:f104::16/64 +RouteMetric=256 diff --git a/test/test-network/systemd-networkd-tests.py b/test/test-network/systemd-networkd-tests.py index c1a017d16b..7c13af58e8 100755 --- a/test/test-network/systemd-networkd-tests.py +++ b/test/test-network/systemd-networkd-tests.py @@ -2329,20 +2329,8 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities): def tearDown(self): tear_down_common() - def test_address_static(self): - # test for #22515. The address will be removed and replaced with /64 prefix. - check_output('ip link add dummy98 type dummy') - check_output('ip link set dev dummy98 up') - check_output('ip -6 address add 2001:db8:0:f101::15/128 dev dummy98') - self.wait_address('dummy98', '2001:db8:0:f101::15/128', ipv='-6') - check_output('ip -4 address add 10.3.2.3/16 brd 10.3.255.250 scope global label dummy98:hoge dev dummy98') - self.wait_address('dummy98', '10.3.2.3/16 brd 10.3.255.250', ipv='-4') - - copy_network_unit('25-address-static.network', '12-dummy.netdev') - start_networkd() - - self.wait_online(['dummy98:routable']) - + def verify_address_static(self, route_metric): + # IPv4 addresses output = check_output('ip -4 address show dev dummy98') print(output) self.assertIn('inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98', output) @@ -2351,16 +2339,13 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities): self.assertIn('inet 10.7.8.9/16 brd 10.7.255.255 scope link deprecated dummy98', output) self.assertIn('inet 10.8.8.1/16 scope global dummy98', output) self.assertIn('inet 10.8.8.2/16 brd 10.8.8.128 scope global secondary dummy98', output) - self.assertRegex(output, 'inet 10.9.0.1/16 (metric 128 |)brd 10.9.255.255 scope global dummy98') - - # test for ENOBUFS issue #17012 - for i in range(1, 254): - self.assertIn(f'inet 10.3.3.{i}/16 brd 10.3.255.255', output) + self.assertRegex(output, rf'inet 10.9.0.1/16 (metric {route_metric} |)brd 10.9.255.255 scope global dummy98') # invalid sections self.assertNotIn('10.10.0.1/16', output) self.assertNotIn('10.10.0.2/16', output) + # address labels output = check_output('ip -4 address show dev dummy98 label 32') self.assertIn('inet 10.3.2.3/16 brd 10.3.255.255 scope global 32', output) @@ -2373,10 +2358,15 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities): output = check_output('ip -4 address show dev dummy98 label 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 -4 route show dev dummy98') + # check metric of prefix route + output = check_output('ip -4 route show dev dummy98 10.9.0.0/16') print(output) - self.assertIn('10.9.0.0/16 proto kernel scope link src 10.9.0.1 metric 128', output) + self.assertIn(f'10.9.0.0/16 proto kernel scope link src 10.9.0.1 metric {route_metric}', output) + output = check_output('ip -6 route show dev dummy98 2001:db8:0:f104::/64') + print(output) + self.assertIn(f'2001:db8:0:f104::/64 proto kernel metric {route_metric}', output) + # IPv6 addresses output = check_output('ip -6 address show dev dummy98') print(output) self.assertIn('inet6 2001:db8:0:f101::15/64 scope global', output) @@ -2384,11 +2374,40 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities): 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.assertRegex(output, rf'inet6 2001:db8:0:f104::16/64 (metric {route_metric} |)scope global') 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') + # netlabel self.check_netlabel('dummy98', r'10\.4\.3\.0/24') + output = check_output(*networkctl_cmd, '--json=short', 'status', env=env) + check_json(output) + + def test_address_static(self): + # test for #22515. The address will be removed and replaced with /64 prefix. + check_output('ip link add dummy98 type dummy') + check_output('ip link set dev dummy98 up') + check_output('ip -6 address add 2001:db8:0:f101::15/128 dev dummy98') + self.wait_address('dummy98', '2001:db8:0:f101::15/128', ipv='-6') + check_output('ip -4 address add 10.3.2.3/16 brd 10.3.255.250 scope global label dummy98:hoge dev dummy98') + self.wait_address('dummy98', '10.3.2.3/16 brd 10.3.255.250', ipv='-4') + + copy_network_unit('25-address-static.network', '12-dummy.netdev', copy_dropins=False) + start_networkd() + + self.wait_online(['dummy98:routable']) + self.verify_address_static(route_metric=128) + + copy_network_unit('25-address-static.network.d/10-override-route-metric.conf') + networkctl_reload() + self.wait_online(['dummy98:routable']) + self.verify_address_static(route_metric=256) + + networkctl_reconfigure('dummy98') + self.wait_online(['dummy98:routable']) + self.verify_address_static(route_metric=256) + # Tests for #20891. # 1. set preferred lifetime forever to drop the deprecated flag for testing #20891. check_output('ip address change 10.7.8.9/16 dev dummy98 preferred_lft forever') @@ -2412,14 +2431,20 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities): print(output) self.assertIn('inet6 2001:db8:1:f101::1/64 scope global deprecated', output) - # test for ENOBUFS issue #17012 + # test for ENOBUFS issue #17012 (with reload) + copy_network_unit('25-address-static.network.d/10-many-address.conf') + networkctl_reload() + self.wait_online(['dummy98:routable']) output = check_output('ip -4 address show dev dummy98') for i in range(1, 254): self.assertIn(f'inet 10.3.3.{i}/16 brd 10.3.255.255', output) - output = check_output(*networkctl_cmd, '--json=short', 'status', env=env) - check_json(output) - + # (with reconfigure) + networkctl_reconfigure('dummy98') + self.wait_online(['dummy98:routable']) + output = check_output('ip -4 address show dev dummy98') + for i in range(1, 254): + self.assertIn(f'inet 10.3.3.{i}/16 brd 10.3.255.255', output) def test_address_null(self): copy_network_unit('25-address-null.network', '12-dummy.netdev')