From 2a877f4560362eb9a330460c05713edd031c9228 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Wed, 8 Jul 2020 11:19:13 +0900 Subject: [PATCH 01/16] network: set dhcp6_xxx_configured flag after routes/addresses are assigned --- src/network/networkd-dhcp6.c | 122 ++++++++++++++++++++++++++--------- src/network/networkd-dhcp6.h | 1 + src/network/networkd-link.c | 5 +- src/network/networkd-link.h | 9 ++- 4 files changed, 105 insertions(+), 32 deletions(-) diff --git a/src/network/networkd-dhcp6.c b/src/network/networkd-dhcp6.c index 73b49a5ec0..77522afed4 100644 --- a/src/network/networkd-dhcp6.c +++ b/src/network/networkd-dhcp6.c @@ -24,7 +24,6 @@ #include "radv-internal.h" #include "web-util.h" -static int dhcp6_lease_address_acquired(sd_dhcp6_client *client, Link *link); static Link *dhcp6_prefix_get(Manager *m, struct in6_addr *addr); static int dhcp6_prefix_add(Manager *m, struct in6_addr *addr, Link *link); static int dhcp6_prefix_remove_all(Manager *m, Link *link); @@ -33,7 +32,7 @@ static int dhcp6_assign_delegated_prefix(Link *link, const struct in6_addr *pref uint32_t lifetime_preferred, uint32_t lifetime_valid); -static bool dhcp6_get_prefix_delegation(Link *link) { +bool dhcp6_get_prefix_delegation(Link *link) { if (!link->network) return false; @@ -172,11 +171,9 @@ static int dhcp6_pd_prefix_assign(Link *link, struct in6_addr *prefix, if (r < 0) return r; - if (link->network->dhcp6_pd_assign_prefix) { - r = dhcp6_assign_delegated_prefix(link, prefix, prefix_len, lifetime_preferred, lifetime_valid); - if (r < 0) - return r; - } + r = dhcp6_assign_delegated_prefix(link, prefix, prefix_len, lifetime_preferred, lifetime_valid); + if (r < 0) + return r; return 0; } @@ -324,13 +321,25 @@ static int dhcp6_route_handler(sd_netlink *nl, sd_netlink_message *m, Link *link int r; assert(link); + assert(link->dhcp6_route_messages > 0); + + link->dhcp6_route_messages--; if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) return 1; r = sd_netlink_message_get_errno(m); - if (r < 0 && r != -EEXIST) - log_link_message_warning_errno(link, m, r, "Received error when adding unreachable route for DHCPv6 delegated subnet"); + if (r < 0 && r != -EEXIST) { + log_link_message_warning_errno(link, m, r, "Failed to add unreachable route for DHCPv6 delegated subnet"); + link_enter_failed(link); + return 1; + } + + if (link->dhcp6_route_messages == 0) { + log_link_debug(link, "Unreachable routes for DHCPv6 delegated subnets set"); + link->dhcp6_route_configured = true; + link_check_ready(link); + } return 1; } @@ -342,6 +351,8 @@ static int dhcp6_lease_pd_prefix_acquired(sd_dhcp6_client *client, Link *link) { uint8_t pd_prefix_len; int r; + link->dhcp6_route_configured = false; + r = sd_dhcp6_client_get_lease(client, &lease); if (r < 0) return r; @@ -386,6 +397,8 @@ static int dhcp6_lease_pd_prefix_acquired(sd_dhcp6_client *client, Link *link) { pd_prefix_len); continue; } + if (r > 0) + link->dhcp6_route_messages++; log_link_debug(link, "Configuring unreachable route for %s/%u", strnull(buf), pd_prefix_len); @@ -435,6 +448,14 @@ static int dhcp6_lease_pd_prefix_acquired(sd_dhcp6_client *client, Link *link) { * fulfill those with the next available pd delegated prefix. */ } + if (link->dhcp6_route_messages == 0) { + link->dhcp6_route_configured = true; + link_check_ready(link); + } else { + log_link_debug(link, "Setting unreachable routes for DHCPv6 delegated subnets"); + link_set_state(link, LINK_STATE_CONFIGURING); + } + return 0; } @@ -506,6 +527,9 @@ static int dhcp6_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link * int r; assert(link); + assert(link->dhcp6_address_messages > 0); + + link->dhcp6_address_messages--; if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) return 1; @@ -518,10 +542,14 @@ static int dhcp6_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link * } else if (r >= 0) (void) manager_rtnl_process_address(rtnl, m, link->manager); - r = link_request_set_routes(link); - if (r < 0) { - link_enter_failed(link); - return 1; + if (link->dhcp6_address_messages == 0) { + log_link_debug(link, "DHCPv6 addresses set"); + link->dhcp6_address_configured = true; + r = link_request_set_routes(link); + if (r < 0) { + link_enter_failed(link); + return 1; + } } return 1; @@ -556,6 +584,8 @@ static int dhcp6_address_change( r = address_configure(addr, link, dhcp6_address_handler, true); if (r < 0) return log_link_warning_errno(link, r, "Could not assign DHCPv6 address: %m"); + if (r > 0) + link->dhcp6_address_messages++; return 0; } @@ -566,12 +596,14 @@ static int dhcp6_lease_address_acquired(sd_dhcp6_client *client, Link *link) { struct in6_addr ip6_addr; uint32_t lifetime_preferred, lifetime_valid; + + link->dhcp6_address_configured = false; + r = sd_dhcp6_client_get_lease(client, &lease); if (r < 0) return r; sd_dhcp6_lease_reset_address_iter(lease); - while (sd_dhcp6_lease_get_address(lease, &ip6_addr, &lifetime_preferred, &lifetime_valid) >= 0) { @@ -581,6 +613,14 @@ static int dhcp6_lease_address_acquired(sd_dhcp6_client *client, Link *link) { return r; } + if (link->dhcp6_address_messages == 0) { + link->dhcp6_address_configured = true; + return link_request_set_routes(link); + } else { + log_link_debug(link, "Setting DHCPv6 addresses"); + link_set_state(link, LINK_STATE_CONFIGURING); + } + return 0; } @@ -605,7 +645,6 @@ static void dhcp6_handler(sd_dhcp6_client *client, int event, void *userdata) { (void) dhcp6_prefix_remove_all(link->manager, link); link_dirty(link); - link->dhcp6_configured = false; break; case SD_DHCP6_CLIENT_EVENT_IP_ACQUIRE: @@ -617,7 +656,7 @@ static void dhcp6_handler(sd_dhcp6_client *client, int event, void *userdata) { r = dhcp6_lease_pd_prefix_acquired(client, link); if (r < 0) - log_link_debug(link, "DHCPv6 did not receive prefixes to delegate"); + log_link_debug_errno(link, r, "DHCPv6 did not receive prefixes to delegate"); _fallthrough_; case SD_DHCP6_CLIENT_EVENT_INFORMATION_REQUEST: @@ -628,7 +667,6 @@ static void dhcp6_handler(sd_dhcp6_client *client, int event, void *userdata) { } link_dirty(link); - link->dhcp6_configured = true; break; default: @@ -665,7 +703,7 @@ int dhcp6_request_address(Link *link, int ir) { r = sd_dhcp6_client_set_address_request(link->dhcp6_client, false); - if (r < 0 ) + if (r < 0) return r; ir = false; @@ -865,21 +903,30 @@ static Link *dhcp6_prefix_get(Manager *m, struct in6_addr *addr) { return hashmap_get(m->dhcp6_prefixes, addr); } -static int dhcp6_route_add_handler(sd_netlink *nl, sd_netlink_message *m, Link *link) { +static int dhcp6_pd_route_handler(sd_netlink *nl, sd_netlink_message *m, Link *link) { int r; assert(link); + assert(link->dhcp6_pd_route_messages > 0); + + link->dhcp6_pd_route_messages--; if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) return 1; r = sd_netlink_message_get_errno(m); if (r < 0 && r != -EEXIST) { - log_link_message_warning_errno(link, m, r, "Received error adding DHCPv6 Prefix Delegation route"); + log_link_message_warning_errno(link, m, r, "Failed to add DHCPv6 Prefix Delegation route"); link_enter_failed(link); return 1; } + if (link->dhcp6_pd_route_messages == 0) { + log_link_debug(link, "DHCPv6 prefix delegation routes set"); + link->dhcp6_pd_route_configured = true; + link_check_ready(link); + } + return 1; } @@ -901,9 +948,14 @@ static int dhcp6_prefix_add(Manager *m, struct in6_addr *addr, Link *link) { route->dst.in6 = *addr; route->dst_prefixlen = 64; - r = route_configure(route, link, dhcp6_route_add_handler); + link->dhcp6_pd_route_configured = false; + link_set_state(link, LINK_STATE_CONFIGURING); + + r = route_configure(route, link, dhcp6_pd_route_handler); if (r < 0) return r; + if (r > 0) + link->dhcp6_pd_route_messages++; (void) in_addr_to_string(AF_INET6, (union in_addr_union *) addr, &buf); log_link_debug(link, "Adding prefix route %s/64", strnull(buf)); @@ -998,26 +1050,33 @@ static int dhcp6_prefix_remove_all(Manager *m, Link *link) { return 0; } -static int dhcp6_assign_delegeted_prefix_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { +static int dhcp6_pd_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { int r; assert(link); + assert(link->dhcp6_pd_address_messages > 0); + + link->dhcp6_pd_address_messages--; if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) return 1; r = sd_netlink_message_get_errno(m); if (r < 0 && r != -EEXIST) { - log_link_message_warning_errno(link, m, r, "Could not set DHCPv6 delegated prefix address "); + log_link_message_warning_errno(link, m, r, "Could not set DHCPv6 delegated prefix address"); link_enter_failed(link); return 1; } else if (r >= 0) (void) manager_rtnl_process_address(rtnl, m, link->manager); - r = link_request_set_routes(link); - if (r < 0) { - link_enter_failed(link); - return 1; + if (link->dhcp6_pd_address_messages == 0) { + log_link_debug(link, "DHCPv6 delegated prefix addresses set"); + link->dhcp6_pd_address_configured = true; + r = link_request_set_routes(link); + if (r < 0) { + link_enter_failed(link); + return 1; + } } return 1; @@ -1036,8 +1095,10 @@ static int dhcp6_assign_delegated_prefix(Link *link, assert(link->network); assert(prefix); - if (!link->network->dhcp6_pd_assign_prefix) + if (!link->network->dhcp6_pd_assign_prefix) { + link->dhcp6_pd_address_configured = true; return 0; + } r = address_new(&address); if (r < 0) @@ -1058,11 +1119,14 @@ static int dhcp6_assign_delegated_prefix(Link *link, address->cinfo.ifa_prefered = lifetime_preferred; address->cinfo.ifa_valid = lifetime_valid; + link->dhcp6_pd_address_configured = false; link_set_state(link, LINK_STATE_CONFIGURING); - r = address_configure(address, link, dhcp6_assign_delegeted_prefix_address_handler, true); + r = address_configure(address, link, dhcp6_pd_address_handler, true); if (r < 0) return log_link_warning_errno(link, r, "Failed to set acquired DHCPv6 delegated prefix address: %m"); + if (r > 0) + link->dhcp6_pd_address_messages++; return 0; } diff --git a/src/network/networkd-dhcp6.h b/src/network/networkd-dhcp6.h index 858559a1e0..cc416b98d2 100644 --- a/src/network/networkd-dhcp6.h +++ b/src/network/networkd-dhcp6.h @@ -17,6 +17,7 @@ typedef enum DHCP6ClientStartMode { typedef struct Link Link; typedef struct Manager Manager; +bool dhcp6_get_prefix_delegation(Link *link); int dhcp6_request_prefix_delegation(Link *link); int dhcp6_configure(Link *link); int dhcp6_request_address(Link *link, int ir); diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 71e6976a30..cd864c690b 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -1141,9 +1141,10 @@ void link_check_ready(Link *link) { in_addr_is_null(AF_INET6, (const union in_addr_union*) &link->ipv6ll_address)) return; - if ((link_dhcp4_enabled(link) || link_dhcp6_enabled(link) || link_ipv6_accept_ra_enabled(link)) && + if ((link_dhcp4_enabled(link) || link_dhcp6_enabled(link) || dhcp6_get_prefix_delegation(link) || link_ipv6_accept_ra_enabled(link)) && !link->dhcp4_configured && - !link->dhcp6_configured && + !(link->dhcp6_address_configured && link->dhcp6_route_configured) && + !(link->dhcp6_pd_address_configured && link->dhcp6_pd_route_configured) && !link->ndisc_configured && !(link_ipv4ll_enabled(link, ADDRESS_FAMILY_FALLBACK_IPV4) && link->ipv4ll_address)) /* When DHCP or RA is enabled, at least one protocol must provide an address, or diff --git a/src/network/networkd-link.h b/src/network/networkd-link.h index f615e7e62d..4333cfa175 100644 --- a/src/network/networkd-link.h +++ b/src/network/networkd-link.h @@ -100,10 +100,17 @@ typedef struct Link { char *lease_file; uint32_t original_mtu; unsigned dhcp4_messages; + unsigned dhcp6_address_messages; + unsigned dhcp6_route_messages; + unsigned dhcp6_pd_address_messages; + unsigned dhcp6_pd_route_messages; bool dhcp4_route_failed:1; bool dhcp4_route_retrying:1; bool dhcp4_configured:1; - bool dhcp6_configured:1; + bool dhcp6_address_configured:1; + bool dhcp6_route_configured:1; + bool dhcp6_pd_address_configured:1; + bool dhcp6_pd_route_configured:1; unsigned ndisc_messages; bool ndisc_configured; From feb596b5c38312a0db01d57ce7d9cb9794693aae Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sun, 12 Jul 2020 05:13:43 +0900 Subject: [PATCH 02/16] network: include error code in the log message --- src/network/networkd-dhcp6.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/network/networkd-dhcp6.c b/src/network/networkd-dhcp6.c index 77522afed4..70be2d6da7 100644 --- a/src/network/networkd-dhcp6.c +++ b/src/network/networkd-dhcp6.c @@ -124,7 +124,7 @@ static int dhcp6_get_preferred_delegated_prefix( r = in_addr_prefix_next(AF_INET6, &prefix, 64); if (r < 0) - return log_link_error_errno(link, r, "Can't allocate another prefix. Out of address space?"); + return log_link_error_errno(link, r, "Can't allocate another prefix. Out of address space?: %m"); } return log_link_warning_errno(link, SYNTHETIC_ERRNO(ERANGE), "Couldn't find a suitable prefix. Ran out of address space."); @@ -482,14 +482,14 @@ int dhcp6_request_prefix_delegation(Link *link) { r = sd_dhcp6_client_get_prefix_delegation(l->dhcp6_client, &enabled); if (r < 0) { - log_link_warning_errno(l, r, "Cannot get prefix delegation when adding new link"); + log_link_warning_errno(l, r, "Cannot get prefix delegation when adding new link: %m"); continue; } if (enabled == 0) { r = sd_dhcp6_client_set_prefix_delegation(l->dhcp6_client, 1); if (r < 0) { - log_link_warning_errno(l, r, "Cannot enable prefix delegation when adding new link"); + log_link_warning_errno(l, r, "Cannot enable prefix delegation when adding new link: 5m"); continue; } } @@ -507,13 +507,13 @@ int dhcp6_request_prefix_delegation(Link *link) { r = sd_dhcp6_client_stop(l->dhcp6_client); if (r < 0) { - log_link_warning_errno(l, r, "Cannot stop DHCPv6 prefix delegation client after adding new link"); + log_link_warning_errno(l, r, "Cannot stop DHCPv6 prefix delegation client after adding new link: %m"); continue; } r = sd_dhcp6_client_start(l->dhcp6_client); if (r < 0) { - log_link_warning_errno(l, r, "Cannot restart DHCPv6 prefix delegation client after adding new link"); + log_link_warning_errno(l, r, "Cannot restart DHCPv6 prefix delegation client after adding new link: %m"); continue; } @@ -656,7 +656,7 @@ static void dhcp6_handler(sd_dhcp6_client *client, int event, void *userdata) { r = dhcp6_lease_pd_prefix_acquired(client, link); if (r < 0) - log_link_debug_errno(link, r, "DHCPv6 did not receive prefixes to delegate"); + log_link_debug_errno(link, r, "DHCPv6 did not receive prefixes to delegate: %m"); _fallthrough_; case SD_DHCP6_CLIENT_EVENT_INFORMATION_REQUEST: @@ -850,7 +850,6 @@ int dhcp6_configure(Link *link) { log_link_debug(link, "DHCP6 CLIENT: Failed to set request flag for '%u' already exists, ignoring.", option); continue; } - if (r < 0) return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set request flag for '%u': %m", option); } From a4623f84edca883ab9bf046a58234b375a500d13 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sun, 12 Jul 2020 05:08:57 +0900 Subject: [PATCH 03/16] network: add a debugging log --- src/network/networkd-ndisc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/network/networkd-ndisc.c b/src/network/networkd-ndisc.c index 563901e33b..1237524c16 100644 --- a/src/network/networkd-ndisc.c +++ b/src/network/networkd-ndisc.c @@ -820,6 +820,7 @@ static void ndisc_handler(sd_ndisc *nd, sd_ndisc_event event, sd_ndisc_router *r break; case SD_NDISC_EVENT_TIMEOUT: + log_link_debug(link, "NDISC handler get timeout event"); link->ndisc_configured = true; link_check_ready(link); From eb01a2dfb140cf1a4ac197f0219e65bb02e1f6f4 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sat, 11 Jul 2020 00:36:38 +0900 Subject: [PATCH 04/16] network: make link_request_set_nexthop() static --- src/network/networkd-link.c | 2 +- src/network/networkd-link.h | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index cd864c690b..03ae8a4bd4 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -972,7 +972,7 @@ static int nexthop_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) return 1; } -int link_request_set_nexthop(Link *link) { +static int link_request_set_nexthop(Link *link) { NextHop *nh; int r; diff --git a/src/network/networkd-link.h b/src/network/networkd-link.h index 4333cfa175..866121bfe9 100644 --- a/src/network/networkd-link.h +++ b/src/network/networkd-link.h @@ -224,7 +224,6 @@ uint32_t link_get_vrf_table(Link *link); uint32_t link_get_dhcp_route_table(Link *link); uint32_t link_get_ipv6_accept_ra_route_table(Link *link); int link_request_set_routes(Link *link); -int link_request_set_nexthop(Link *link); int link_reconfigure(Link *link, bool force); From 491b79aeac323909e8cef60ba6e91e27fd731679 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Wed, 8 Jul 2020 15:56:47 +0900 Subject: [PATCH 05/16] test-network: set IPv6AcceptRA=no if no dynamic addresses are not required --- test/test-network/conf/23-bond199.network | 3 +++ test/test-network/conf/23-emit-lldp.network | 1 + test/test-network/conf/24-keep-configuration-static.network | 1 + test/test-network/conf/24-lldp.network | 1 + test/test-network/conf/24-search-domain.network | 1 + test/test-network/conf/25-address-link-section.network | 3 +++ .../conf/25-address-preferred-lifetime-zero.network | 2 ++ test/test-network/conf/25-fibrule-invert.network | 3 +++ test/test-network/conf/25-fibrule-port-range.network | 3 +++ test/test-network/conf/25-fibrule-uidrange.network | 3 +++ test/test-network/conf/25-gateway-next-static.network | 1 + test/test-network/conf/25-gateway-static.network | 1 + test/test-network/conf/25-ipv6-address-label-section.network | 3 +++ test/test-network/conf/25-route-vrf.network | 1 + test/test-network/conf/25-vrf.network | 3 +++ test/test-network/conf/6rd.network | 1 + test/test-network/conf/erspan.network | 1 + test/test-network/conf/gretap.network | 1 + test/test-network/conf/gretun.network | 1 + test/test-network/conf/ip6gretap.network | 1 + test/test-network/conf/ip6gretun.network | 1 + test/test-network/conf/ip6tnl.network | 1 + test/test-network/conf/ipip.network | 1 + test/test-network/conf/ipvlan.network | 1 + test/test-network/conf/ipvtap.network | 1 + test/test-network/conf/isatap.network | 1 + test/test-network/conf/macvlan.network | 1 + test/test-network/conf/macvtap.network | 1 + test/test-network/conf/routing-policy-rule-dummy98.network | 3 +++ test/test-network/conf/routing-policy-rule-test1.network | 3 +++ test/test-network/conf/sit.network | 1 + test/test-network/conf/state-file-tests.network | 1 + test/test-network/conf/vti.network | 1 + test/test-network/conf/vti6.network | 1 + 34 files changed, 53 insertions(+) diff --git a/test/test-network/conf/23-bond199.network b/test/test-network/conf/23-bond199.network index 31e5d12f75..cad6511566 100644 --- a/test/test-network/conf/23-bond199.network +++ b/test/test-network/conf/23-bond199.network @@ -1,2 +1,5 @@ [Match] Name=bond199 + +[Network] +IPv6AcceptRA=no diff --git a/test/test-network/conf/23-emit-lldp.network b/test/test-network/conf/23-emit-lldp.network index de35045388..9edaf871b4 100644 --- a/test/test-network/conf/23-emit-lldp.network +++ b/test/test-network/conf/23-emit-lldp.network @@ -2,4 +2,5 @@ Name=veth-peer [Network] +IPv6AcceptRA=no EmitLLDP=yes diff --git a/test/test-network/conf/24-keep-configuration-static.network b/test/test-network/conf/24-keep-configuration-static.network index 0c65a1d9e2..7602927d81 100644 --- a/test/test-network/conf/24-keep-configuration-static.network +++ b/test/test-network/conf/24-keep-configuration-static.network @@ -2,4 +2,5 @@ Name=dummy98 [Network] +IPv6AcceptRA=no KeepConfiguration=static diff --git a/test/test-network/conf/24-lldp.network b/test/test-network/conf/24-lldp.network index fbdfb1b672..84723138f2 100644 --- a/test/test-network/conf/24-lldp.network +++ b/test/test-network/conf/24-lldp.network @@ -2,4 +2,5 @@ Name=veth99 [Network] +IPv6AcceptRA=no LLDP=yes diff --git a/test/test-network/conf/24-search-domain.network b/test/test-network/conf/24-search-domain.network index 124af438a3..5c37d2f61f 100644 --- a/test/test-network/conf/24-search-domain.network +++ b/test/test-network/conf/24-search-domain.network @@ -2,6 +2,7 @@ Name=dummy98 [Network] +IPv6AcceptRA=no Address=192.168.42.100/24 DNS=192.168.42.1 Domains= one two three four five six seven eight nine ten diff --git a/test/test-network/conf/25-address-link-section.network b/test/test-network/conf/25-address-link-section.network index 759e83c325..d6ab340271 100644 --- a/test/test-network/conf/25-address-link-section.network +++ b/test/test-network/conf/25-address-link-section.network @@ -3,3 +3,6 @@ Name=dummy98 [Link] MACAddress=00:01:02:aa:bb:cc + +[Network] +IPv6AcceptRA=no diff --git a/test/test-network/conf/25-address-preferred-lifetime-zero.network b/test/test-network/conf/25-address-preferred-lifetime-zero.network index a1e7605103..d3d02d282f 100644 --- a/test/test-network/conf/25-address-preferred-lifetime-zero.network +++ b/test/test-network/conf/25-address-preferred-lifetime-zero.network @@ -2,6 +2,8 @@ Name=dummy98 [Network] +IPv6AcceptRA=no + # these lines are ignored Address=hogehoge Address=foofoo diff --git a/test/test-network/conf/25-fibrule-invert.network b/test/test-network/conf/25-fibrule-invert.network index bcca0c27ab..b8b368fe5a 100644 --- a/test/test-network/conf/25-fibrule-invert.network +++ b/test/test-network/conf/25-fibrule-invert.network @@ -1,6 +1,9 @@ [Match] Name=test1 +[Network] +IPv6AcceptRA=no + [RoutingPolicyRule] TypeOfService=0x08 Table=7 diff --git a/test/test-network/conf/25-fibrule-port-range.network b/test/test-network/conf/25-fibrule-port-range.network index 36646ec0ff..77874b3440 100644 --- a/test/test-network/conf/25-fibrule-port-range.network +++ b/test/test-network/conf/25-fibrule-port-range.network @@ -1,6 +1,9 @@ [Match] Name=test1 +[Network] +IPv6AcceptRA=no + [RoutingPolicyRule] TypeOfService=0x08 Table=7 diff --git a/test/test-network/conf/25-fibrule-uidrange.network b/test/test-network/conf/25-fibrule-uidrange.network index f42dfee325..44716e396a 100644 --- a/test/test-network/conf/25-fibrule-uidrange.network +++ b/test/test-network/conf/25-fibrule-uidrange.network @@ -1,6 +1,9 @@ [Match] Name=test1 +[Network] +IPv6AcceptRA=no + [RoutingPolicyRule] TypeOfService=0x08 Table=7 diff --git a/test/test-network/conf/25-gateway-next-static.network b/test/test-network/conf/25-gateway-next-static.network index dfac8f48cd..908e58881e 100644 --- a/test/test-network/conf/25-gateway-next-static.network +++ b/test/test-network/conf/25-gateway-next-static.network @@ -2,5 +2,6 @@ Name=dummy98 [Network] +IPv6AcceptRA=no Address=149.10.124.58/28 Gateway=149.10.124.60 diff --git a/test/test-network/conf/25-gateway-static.network b/test/test-network/conf/25-gateway-static.network index 448a21f2b9..1ea184fa2f 100644 --- a/test/test-network/conf/25-gateway-static.network +++ b/test/test-network/conf/25-gateway-static.network @@ -2,5 +2,6 @@ Name=dummy98 [Network] +IPv6AcceptRA=no Address=149.10.124.58/28 Gateway=149.10.124.59 diff --git a/test/test-network/conf/25-ipv6-address-label-section.network b/test/test-network/conf/25-ipv6-address-label-section.network index 945b7dcc45..0742ad5849 100644 --- a/test/test-network/conf/25-ipv6-address-label-section.network +++ b/test/test-network/conf/25-ipv6-address-label-section.network @@ -1,6 +1,9 @@ [Match] Name=dummy98 +[Network] +IPv6AcceptRA=no + [IPv6AddressLabel] Label=4444 Prefix=2004:da8:1:0::/64 diff --git a/test/test-network/conf/25-route-vrf.network b/test/test-network/conf/25-route-vrf.network index e786066d3f..038dff21aa 100644 --- a/test/test-network/conf/25-route-vrf.network +++ b/test/test-network/conf/25-route-vrf.network @@ -2,6 +2,7 @@ Name=dummy98 [Network] +IPv6AcceptRA=no VRF=vrf99 Address=192.168.100.2/24 Gateway=192.168.100.1 diff --git a/test/test-network/conf/25-vrf.network b/test/test-network/conf/25-vrf.network index 42ce5b1925..d47ecf0789 100644 --- a/test/test-network/conf/25-vrf.network +++ b/test/test-network/conf/25-vrf.network @@ -1,2 +1,5 @@ [Match] Name=vrf99 + +[Network] +IPv6AcceptRA=no diff --git a/test/test-network/conf/6rd.network b/test/test-network/conf/6rd.network index 84e5af0ff0..96bd561ff9 100644 --- a/test/test-network/conf/6rd.network +++ b/test/test-network/conf/6rd.network @@ -2,4 +2,5 @@ Name=dummy98 [Network] +IPv6AcceptRA=no Tunnel=sittun99 diff --git a/test/test-network/conf/erspan.network b/test/test-network/conf/erspan.network index 49364c506c..d1a88cdaaf 100644 --- a/test/test-network/conf/erspan.network +++ b/test/test-network/conf/erspan.network @@ -2,5 +2,6 @@ Name=dummy98 [Network] +IPv6AcceptRA=no Tunnel=erspan99 Tunnel=erspan98 diff --git a/test/test-network/conf/gretap.network b/test/test-network/conf/gretap.network index 1493fcf2b0..1deaab45d6 100644 --- a/test/test-network/conf/gretap.network +++ b/test/test-network/conf/gretap.network @@ -2,5 +2,6 @@ Name=dummy98 [Network] +IPv6AcceptRA=no Tunnel=gretap99 Tunnel=gretap98 diff --git a/test/test-network/conf/gretun.network b/test/test-network/conf/gretun.network index 5510b1c9b6..68d95b1808 100644 --- a/test/test-network/conf/gretun.network +++ b/test/test-network/conf/gretun.network @@ -2,6 +2,7 @@ Name=dummy98 [Network] +IPv6AcceptRA=no Tunnel=gretun99 Tunnel=gretun98 Tunnel=gretun97 diff --git a/test/test-network/conf/ip6gretap.network b/test/test-network/conf/ip6gretap.network index 7ae4e3aea7..8434c62efb 100644 --- a/test/test-network/conf/ip6gretap.network +++ b/test/test-network/conf/ip6gretap.network @@ -2,5 +2,6 @@ Name=dummy98 [Network] +IPv6AcceptRA=no Tunnel=ip6gretap99 Tunnel=ip6gretap98 diff --git a/test/test-network/conf/ip6gretun.network b/test/test-network/conf/ip6gretun.network index 8fbee98851..ce2bbd8792 100644 --- a/test/test-network/conf/ip6gretun.network +++ b/test/test-network/conf/ip6gretun.network @@ -2,6 +2,7 @@ Name=dummy98 [Network] +IPv6AcceptRA=no Tunnel=ip6gretun99 Tunnel=ip6gretun98 Tunnel=ip6gretun97 diff --git a/test/test-network/conf/ip6tnl.network b/test/test-network/conf/ip6tnl.network index 15c6d15d45..7ad1e1b5b1 100644 --- a/test/test-network/conf/ip6tnl.network +++ b/test/test-network/conf/ip6tnl.network @@ -2,6 +2,7 @@ Name=dummy98 [Network] +IPv6AcceptRA=no Tunnel=ip6tnl99 Tunnel=ip6tnl98 Tunnel=ip6tnl97 diff --git a/test/test-network/conf/ipip.network b/test/test-network/conf/ipip.network index ea4b3a1353..c1ef30519c 100644 --- a/test/test-network/conf/ipip.network +++ b/test/test-network/conf/ipip.network @@ -2,6 +2,7 @@ Name=dummy98 [Network] +IPv6AcceptRA=no Tunnel=ipiptun99 Tunnel=ipiptun98 Tunnel=ipiptun97 diff --git a/test/test-network/conf/ipvlan.network b/test/test-network/conf/ipvlan.network index d053220550..b3fccb146f 100644 --- a/test/test-network/conf/ipvlan.network +++ b/test/test-network/conf/ipvlan.network @@ -2,4 +2,5 @@ Name=test1 [Network] +IPv6AcceptRA=no IPVLAN=ipvlan99 diff --git a/test/test-network/conf/ipvtap.network b/test/test-network/conf/ipvtap.network index c81ba52e2d..4549164323 100644 --- a/test/test-network/conf/ipvtap.network +++ b/test/test-network/conf/ipvtap.network @@ -2,4 +2,5 @@ Name=test1 [Network] +IPv6AcceptRA=no IPVTAP=ipvtap99 diff --git a/test/test-network/conf/isatap.network b/test/test-network/conf/isatap.network index e8d03ed6bd..9458330859 100644 --- a/test/test-network/conf/isatap.network +++ b/test/test-network/conf/isatap.network @@ -2,4 +2,5 @@ Name=dummy98 [Network] +IPv6AcceptRA=no Tunnel=isataptun99 diff --git a/test/test-network/conf/macvlan.network b/test/test-network/conf/macvlan.network index a41c1f916c..e18842ca23 100644 --- a/test/test-network/conf/macvlan.network +++ b/test/test-network/conf/macvlan.network @@ -2,4 +2,5 @@ Name=test1 [Network] +IPv6AcceptRA=no MACVLAN=macvlan99 diff --git a/test/test-network/conf/macvtap.network b/test/test-network/conf/macvtap.network index 6ee99ab9ce..956d13fc3a 100644 --- a/test/test-network/conf/macvtap.network +++ b/test/test-network/conf/macvtap.network @@ -2,4 +2,5 @@ Name=test1 [Network] +IPv6AcceptRA=no MACVTAP=macvtap99 diff --git a/test/test-network/conf/routing-policy-rule-dummy98.network b/test/test-network/conf/routing-policy-rule-dummy98.network index 8136c20ae4..804597cec4 100644 --- a/test/test-network/conf/routing-policy-rule-dummy98.network +++ b/test/test-network/conf/routing-policy-rule-dummy98.network @@ -1,6 +1,9 @@ [Match] Name=dummy98 +[Network] +IPv6AcceptRA=no + [RoutingPolicyRule] TypeOfService=0x08 Table=8 diff --git a/test/test-network/conf/routing-policy-rule-test1.network b/test/test-network/conf/routing-policy-rule-test1.network index ffcedc99a2..3594602cbb 100644 --- a/test/test-network/conf/routing-policy-rule-test1.network +++ b/test/test-network/conf/routing-policy-rule-test1.network @@ -1,6 +1,9 @@ [Match] Name=test1 +[Network] +IPv6AcceptRA=no + [RoutingPolicyRule] TypeOfService=0x08 Table=7 diff --git a/test/test-network/conf/sit.network b/test/test-network/conf/sit.network index 79909fcd6b..571c5c93d9 100644 --- a/test/test-network/conf/sit.network +++ b/test/test-network/conf/sit.network @@ -2,6 +2,7 @@ Name=dummy98 [Network] +IPv6AcceptRA=no Tunnel=sittun99 Tunnel=sittun98 Tunnel=sittun97 diff --git a/test/test-network/conf/state-file-tests.network b/test/test-network/conf/state-file-tests.network index d0233841fd..468669c6cc 100644 --- a/test/test-network/conf/state-file-tests.network +++ b/test/test-network/conf/state-file-tests.network @@ -5,6 +5,7 @@ Name=dummy98 RequiredForOnline=routable [Network] +IPv6AcceptRA=no DNS=10.10.10.10 10.10.10.11 NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org Domains=hogehoge ~foofoo diff --git a/test/test-network/conf/vti.network b/test/test-network/conf/vti.network index 761362e482..888e79a79d 100644 --- a/test/test-network/conf/vti.network +++ b/test/test-network/conf/vti.network @@ -2,6 +2,7 @@ Name=dummy98 [Network] +IPv6AcceptRA=no Tunnel=vtitun99 Tunnel=vtitun98 Tunnel=vtitun97 diff --git a/test/test-network/conf/vti6.network b/test/test-network/conf/vti6.network index 60ccb77f56..0916de86dd 100644 --- a/test/test-network/conf/vti6.network +++ b/test/test-network/conf/vti6.network @@ -2,6 +2,7 @@ Name=dummy98 [Network] +IPv6AcceptRA=no Tunnel=vti6tun99 Tunnel=vti6tun98 Tunnel=vti6tun97 From c5fcd8a70ad55ab9f84fe6ae86601cd00628687c Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sun, 12 Jul 2020 06:26:34 +0900 Subject: [PATCH 06/16] test-network: check assigned address is not tentative state --- test/test-network/systemd-networkd-tests.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/test-network/systemd-networkd-tests.py b/test/test-network/systemd-networkd-tests.py index 4dca56f7dc..31ef04af8a 100755 --- a/test/test-network/systemd-networkd-tests.py +++ b/test/test-network/systemd-networkd-tests.py @@ -3168,6 +3168,12 @@ class NetworkdDHCPClientTests(unittest.TestCase, Utilities): self.assertRegex(output, '2600::') self.assertNotRegex(output, '192.168.5') + output = check_output('ip addr show dev veth99') + print(output) + self.assertRegex(output, '2600::') + self.assertNotRegex(output, '192.168.5') + self.assertNotRegex(output, 'tentative') + # Confirm that ipv6 token is not set in the kernel output = check_output('ip token show dev veth99') print(output) From 39373cb98425a7499ea65a1344947808035388d6 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sun, 12 Jul 2020 08:23:19 +0900 Subject: [PATCH 07/16] network: add debugging log why link is not in configured state yet --- src/network/networkd-link.c | 79 +++++++++++++++++++++++++++---------- 1 file changed, 59 insertions(+), 20 deletions(-) diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 03ae8a4bd4..45ee1e13ef 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -1085,71 +1085,110 @@ void link_check_ready(Link *link) { assert(link); - if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) + if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) { + log_link_debug(link, "%s(): link is in failed or linger state.", __func__); return; + } if (!link->network) return; - if (!link->addresses_configured) + if (!link->addresses_configured) { + log_link_debug(link, "%s(): static addresses are not configured.", __func__); return; + } - if (!link->neighbors_configured) + if (!link->neighbors_configured) { + log_link_debug(link, "%s(): static neighbors are not configured.", __func__); return; + } SET_FOREACH(a, link->addresses, i) - if (!address_is_ready(a)) + if (!address_is_ready(a)) { + _cleanup_free_ char *str = NULL; + + (void) in_addr_to_string(a->family, &a->in_addr, &str); + log_link_debug(link, "%s(): an address %s/%d is not ready.", __func__, strnull(str), a->prefixlen); return; + } if (!link->addresses_ready) { link->addresses_ready = true; r = link_request_set_routes(link); if (r < 0) link_enter_failed(link); + log_link_debug(link, "%s(): static addresses are configured. Configuring static routes.", __func__); return; } - if (!link->static_routes_configured) + if (!link->static_routes_configured) { + log_link_debug(link, "%s(): static routes are not configured.", __func__); return; + } if (!link->static_routes_ready) { link->static_routes_ready = true; r = link_request_set_nexthop(link); if (r < 0) link_enter_failed(link); + log_link_debug(link, "%s(): static routes are configured. Configuring static nexthops.", __func__); return; } - if (!link->static_nexthops_configured) + if (!link->static_nexthops_configured) { + log_link_debug(link, "%s(): static nexthops are not configured.", __func__); return; + } - if (!link->routing_policy_rules_configured) + if (!link->routing_policy_rules_configured) { + log_link_debug(link, "%s(): static routing policy rules are not configured.", __func__); return; + } - if (!link->tc_configured) + if (!link->tc_configured) { + log_link_debug(link, "%s(): traffic controls are not configured.", __func__); return; + } - if (!link->sr_iov_configured) + if (!link->sr_iov_configured) { + log_link_debug(link, "%s(): SR-IOV is not configured.", __func__); return; + } if (link_has_carrier(link) || !link->network->configure_without_carrier) { - if (link_ipv4ll_enabled(link, ADDRESS_FAMILY_IPV4) && !link->ipv4ll_address) + if (link_ipv4ll_enabled(link, ADDRESS_FAMILY_IPV4) && !link->ipv4ll_address) { + log_link_debug(link, "%s(): IPv4LL is not configured.", __func__); return; + } if (link_ipv6ll_enabled(link) && - in_addr_is_null(AF_INET6, (const union in_addr_union*) &link->ipv6ll_address)) + in_addr_is_null(AF_INET6, (const union in_addr_union*) &link->ipv6ll_address)) { + log_link_debug(link, "%s(): IPv6LL is not configured.", __func__); return; + } - if ((link_dhcp4_enabled(link) || link_dhcp6_enabled(link) || dhcp6_get_prefix_delegation(link) || link_ipv6_accept_ra_enabled(link)) && - !link->dhcp4_configured && - !(link->dhcp6_address_configured && link->dhcp6_route_configured) && - !(link->dhcp6_pd_address_configured && link->dhcp6_pd_route_configured) && - !link->ndisc_configured && - !(link_ipv4ll_enabled(link, ADDRESS_FAMILY_FALLBACK_IPV4) && link->ipv4ll_address)) - /* When DHCP or RA is enabled, at least one protocol must provide an address, or - * an IPv4ll fallback address must be configured. */ - return; + if (link_dhcp4_enabled(link) || link_dhcp6_enabled(link) || dhcp6_get_prefix_delegation(link) || link_ipv6_accept_ra_enabled(link)) { + if (!link->dhcp4_configured && + !(link->dhcp6_address_configured && link->dhcp6_route_configured) && + !(link->dhcp6_pd_address_configured && link->dhcp6_pd_route_configured) && + !link->ndisc_configured && + !(link_ipv4ll_enabled(link, ADDRESS_FAMILY_FALLBACK_IPV4) && link->ipv4ll_address)) { + /* When DHCP or RA is enabled, at least one protocol must provide an address, or + * an IPv4ll fallback address must be configured. */ + log_link_debug(link, "%s(): dynamic addresses or routes are not configured.", __func__); + return; + } + + log_link_debug(link, "%s(): dhcp4:%s dhcp6_addresses:%s dhcp_routes:%s dhcp_pd_addresses:%s dhcp_pd_routes:%s ndisc:%s", + __func__, + yes_no(link->dhcp4_configured), + yes_no(link->dhcp6_address_configured), + yes_no(link->dhcp6_route_configured), + yes_no(link->dhcp6_pd_address_configured), + yes_no(link->dhcp6_pd_route_configured), + yes_no(link->ndisc_configured)); + } } if (link->state != LINK_STATE_CONFIGURED) From 571f953934ad8369a1ef2761d6da1e03d3bbd48a Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sun, 12 Jul 2020 09:28:53 +0900 Subject: [PATCH 08/16] test-network: wait for addresses are not in tentative state --- test/networkd-test.py | 2 +- test/test-network/systemd-networkd-tests.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/networkd-test.py b/test/networkd-test.py index 618237161a..b225694819 100755 --- a/test/networkd-test.py +++ b/test/networkd-test.py @@ -376,7 +376,7 @@ DHCP={} # IPv6, but we want to wait for both for _ in range(10): out = subprocess.check_output(['ip', 'a', 'show', 'dev', self.iface]) - if b'state UP' in out and b'inet6 2600' in out and b'inet 192.168' in out: + if b'state UP' in out and b'inet6 2600' in out and b'inet 192.168' in out and b'tentative' not in out: break time.sleep(1) else: diff --git a/test/test-network/systemd-networkd-tests.py b/test/test-network/systemd-networkd-tests.py index 31ef04af8a..2d7f915850 100755 --- a/test/test-network/systemd-networkd-tests.py +++ b/test/test-network/systemd-networkd-tests.py @@ -557,7 +557,7 @@ class Utilities(): if i > 0: time.sleep(1) output = check_output(f'ip {ipv} address show dev {link} scope {scope}') - if re.search(address_regex, output): + if re.search(address_regex, output) and 'tentative' not in output: break else: self.assertRegex(output, address_regex) From 01c344bdd46ce2582a0a88e4ac680785c89632bc Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sun, 12 Jul 2020 13:26:53 +0900 Subject: [PATCH 09/16] network: ndisc: do not ignore remaining addresses Follow-up for c24c83dc67a63c88b0a537f4fa7f605b1fcbac39. --- src/network/networkd-ndisc.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/network/networkd-ndisc.c b/src/network/networkd-ndisc.c index 1237524c16..6534effe27 100644 --- a/src/network/networkd-ndisc.c +++ b/src/network/networkd-ndisc.c @@ -404,7 +404,7 @@ static int ndisc_router_process_autonomous_prefix(Link *link, sd_ndisc_router *r } else if (lifetime_valid > 0) a->cinfo.ifa_valid = lifetime_valid; else - return 0; /* see RFC4862 section 5.5.3.d */ + continue; /* see RFC4862 section 5.5.3.d */ if (a->cinfo.ifa_valid == 0) continue; @@ -415,7 +415,6 @@ static int ndisc_router_process_autonomous_prefix(Link *link, sd_ndisc_router *r link_enter_failed(link); return r; } - if (r > 0) link->ndisc_messages++; } From d98c546dac628c119f4a1ad1de17308a79541341 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sun, 12 Jul 2020 13:55:44 +0900 Subject: [PATCH 10/16] network: ndisc: split ndisc_configured flag into for addresses and routes --- src/network/networkd-link.c | 7 ++-- src/network/networkd-link.h | 6 ++- src/network/networkd-ndisc.c | 73 ++++++++++++++++++++++-------------- 3 files changed, 52 insertions(+), 34 deletions(-) diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 45ee1e13ef..c6fa56cc6a 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -1172,7 +1172,7 @@ void link_check_ready(Link *link) { if (!link->dhcp4_configured && !(link->dhcp6_address_configured && link->dhcp6_route_configured) && !(link->dhcp6_pd_address_configured && link->dhcp6_pd_route_configured) && - !link->ndisc_configured && + !(link->ndisc_addresses_configured && link->ndisc_routes_configured) && !(link_ipv4ll_enabled(link, ADDRESS_FAMILY_FALLBACK_IPV4) && link->ipv4ll_address)) { /* When DHCP or RA is enabled, at least one protocol must provide an address, or * an IPv4ll fallback address must be configured. */ @@ -1180,14 +1180,15 @@ void link_check_ready(Link *link) { return; } - log_link_debug(link, "%s(): dhcp4:%s dhcp6_addresses:%s dhcp_routes:%s dhcp_pd_addresses:%s dhcp_pd_routes:%s ndisc:%s", + log_link_debug(link, "%s(): dhcp4:%s dhcp6_addresses:%s dhcp_routes:%s dhcp_pd_addresses:%s dhcp_pd_routes:%s ndisc_addresses:%s ndisc_routes:%s", __func__, yes_no(link->dhcp4_configured), yes_no(link->dhcp6_address_configured), yes_no(link->dhcp6_route_configured), yes_no(link->dhcp6_pd_address_configured), yes_no(link->dhcp6_pd_route_configured), - yes_no(link->ndisc_configured)); + yes_no(link->ndisc_addresses_configured), + yes_no(link->ndisc_routes_configured)); } } diff --git a/src/network/networkd-link.h b/src/network/networkd-link.h index 866121bfe9..d0340b9719 100644 --- a/src/network/networkd-link.h +++ b/src/network/networkd-link.h @@ -112,8 +112,10 @@ typedef struct Link { bool dhcp6_pd_address_configured:1; bool dhcp6_pd_route_configured:1; - unsigned ndisc_messages; - bool ndisc_configured; + unsigned ndisc_addresses_messages; + unsigned ndisc_routes_messages; + bool ndisc_addresses_configured:1; + bool ndisc_routes_configured:1; sd_ipv4ll *ipv4ll; bool ipv4ll_address:1; diff --git a/src/network/networkd-ndisc.c b/src/network/networkd-ndisc.c index 6534effe27..ac5b242fc1 100644 --- a/src/network/networkd-ndisc.c +++ b/src/network/networkd-ndisc.c @@ -82,64 +82,60 @@ static int make_stableprivate_address(Link *link, const struct in6_addr *prefix, return 0; } -static int ndisc_netlink_route_message_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { +static int ndisc_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { int r; assert(link); - assert(link->ndisc_messages > 0); + assert(link->ndisc_routes_messages > 0); - link->ndisc_messages--; + link->ndisc_routes_messages--; if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) return 1; r = sd_netlink_message_get_errno(m); if (r < 0 && r != -EEXIST) { - log_link_message_error_errno(link, m, r, "Could not set NDisc route or address"); + log_link_message_error_errno(link, m, r, "Could not set NDisc route"); link_enter_failed(link); return 1; } - if (link->ndisc_messages == 0) { - link->ndisc_configured = true; - r = link_request_set_routes(link); - if (r < 0) { - link_enter_failed(link); - return 1; - } + if (link->ndisc_routes_messages == 0) { + log_link_debug(link, "NDisc routes set."); + link->ndisc_routes_configured = true; link_check_ready(link); } return 1; } -static int ndisc_netlink_address_message_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { +static int ndisc_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { int r; assert(link); - assert(link->ndisc_messages > 0); + assert(link->ndisc_addresses_messages > 0); - link->ndisc_messages--; + link->ndisc_addresses_messages--; if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) return 1; r = sd_netlink_message_get_errno(m); if (r < 0 && r != -EEXIST) { - log_link_message_error_errno(link, m, r, "Could not set NDisc route or address"); + log_link_message_error_errno(link, m, r, "Could not set NDisc address"); link_enter_failed(link); return 1; } else if (r >= 0) (void) manager_rtnl_process_address(rtnl, m, link->manager); - if (link->ndisc_messages == 0) { - link->ndisc_configured = true; + if (link->ndisc_addresses_messages == 0) { + log_link_debug(link, "NDisc SLAAC addresses set."); + link->ndisc_addresses_configured = true; r = link_request_set_routes(link); if (r < 0) { link_enter_failed(link); return 1; } - link_check_ready(link); } return 1; @@ -223,14 +219,14 @@ static int ndisc_router_process_default(Link *link, sd_ndisc_router *rt) { route->lifetime = time_now + lifetime * USEC_PER_SEC; route->mtu = mtu; - r = route_configure(route, link, ndisc_netlink_route_message_handler); + r = route_configure(route, link, ndisc_route_handler); if (r < 0) { log_link_warning_errno(link, r, "Could not set default route: %m"); link_enter_failed(link); return r; } if (r > 0) - link->ndisc_messages++; + link->ndisc_routes_messages++; Route *route_gw; LIST_FOREACH(routes, route_gw, link->network->static_routes) { @@ -242,14 +238,14 @@ static int ndisc_router_process_default(Link *link, sd_ndisc_router *rt) { route_gw->gw = gateway; - r = route_configure(route_gw, link, ndisc_netlink_route_message_handler); + r = route_configure(route_gw, link, ndisc_route_handler); if (r < 0) { log_link_error_errno(link, r, "Could not set gateway: %m"); link_enter_failed(link); return r; } if (r > 0) - link->ndisc_messages++; + link->ndisc_routes_messages++; } return 0; @@ -409,14 +405,14 @@ static int ndisc_router_process_autonomous_prefix(Link *link, sd_ndisc_router *r if (a->cinfo.ifa_valid == 0) continue; - r = address_configure(a, link, ndisc_netlink_address_message_handler, true); + r = address_configure(a, link, ndisc_address_handler, true); if (r < 0) { log_link_warning_errno(link, r, "Could not set SLAAC address: %m"); link_enter_failed(link); return r; } if (r > 0) - link->ndisc_messages++; + link->ndisc_addresses_messages++; } return 0; @@ -460,14 +456,14 @@ static int ndisc_router_process_onlink_prefix(Link *link, sd_ndisc_router *rt) { if (r < 0) return log_link_error_errno(link, r, "Failed to get prefix address: %m"); - r = route_configure(route, link, ndisc_netlink_route_message_handler); + r = route_configure(route, link, ndisc_route_handler); if (r < 0) { log_link_warning_errno(link, r, "Could not set prefix route: %m"); link_enter_failed(link); return r; } if (r > 0) - link->ndisc_messages++; + link->ndisc_routes_messages++; return 0; } @@ -522,14 +518,14 @@ static int ndisc_router_process_route(Link *link, sd_ndisc_router *rt) { if (r < 0) return log_link_error_errno(link, r, "Failed to get route address: %m"); - r = route_configure(route, link, ndisc_netlink_route_message_handler); + r = route_configure(route, link, ndisc_route_handler); if (r < 0) { log_link_warning_errno(link, r, "Could not set additional route: %m"); link_enter_failed(link); return r; } if (r > 0) - link->ndisc_messages++; + link->ndisc_routes_messages++; return 0; } @@ -815,12 +811,31 @@ static void ndisc_handler(sd_ndisc *nd, sd_ndisc_event event, sd_ndisc_router *r switch (event) { case SD_NDISC_EVENT_ROUTER: + link->ndisc_addresses_configured = false; + link->ndisc_routes_configured = false; + (void) ndisc_router_handler(link, rt); + + if (link->ndisc_addresses_messages == 0) + link->ndisc_addresses_configured = true; + else + log_link_debug(link, "Setting SLAAC addresses."); + + if (link->ndisc_routes_messages == 0) + link->ndisc_routes_configured = true; + else + log_link_debug(link, "Setting NDisc routes."); + + if (link->ndisc_addresses_configured && link->ndisc_routes_configured) + link_check_ready(link); + else + link_set_state(link, LINK_STATE_CONFIGURING); break; case SD_NDISC_EVENT_TIMEOUT: log_link_debug(link, "NDISC handler get timeout event"); - link->ndisc_configured = true; + link->ndisc_addresses_configured = true; + link->ndisc_routes_configured = true; link_check_ready(link); break; From 659ad3a0af7ff0cef342db9e0388ef731c9e8987 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sun, 12 Jul 2020 14:57:45 +0900 Subject: [PATCH 11/16] network: do not make link in configured state when no address is assigned When DHCP6 and RA are enabled, and RA does not provide any addresses, then link may become configured state even if no address is assigned, due to the time-lag between RA completion and DHCP reply. This makes if DHCP is explicitly enabled, then link must have at least one valid address to be in the configured state. --- src/network/networkd-link.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index c6fa56cc6a..4c16255a75 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -1168,6 +1168,11 @@ void link_check_ready(Link *link) { return; } + if ((link_dhcp4_enabled(link) || link_dhcp6_enabled(link)) && set_isempty(link->addresses)) { + log_link_debug(link, "%s(): DHCP4 or DHCP6 is enabled but no address is assigned yet.", __func__); + return; + } + if (link_dhcp4_enabled(link) || link_dhcp6_enabled(link) || dhcp6_get_prefix_delegation(link) || link_ipv6_accept_ra_enabled(link)) { if (!link->dhcp4_configured && !(link->dhcp6_address_configured && link->dhcp6_route_configured) && From 0c816fcc7b7b1d47bc0616edada91a44f41f1c0d Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Mon, 13 Jul 2020 03:12:11 +0900 Subject: [PATCH 12/16] network: make link_request_set_nexthop() called from link_request_set_routes() or route_handler() Then we can drop static_routes_ready() flag. --- src/network/networkd-dhcp4.c | 6 ++++++ src/network/networkd-dhcp6.c | 11 ++++++++++- src/network/networkd-link.c | 17 ++++------------- src/network/networkd-link.h | 1 - src/network/networkd-ndisc.c | 9 ++++++++- 5 files changed, 28 insertions(+), 16 deletions(-) diff --git a/src/network/networkd-dhcp4.c b/src/network/networkd-dhcp4.c index 37b16315e5..38cf3f287b 100644 --- a/src/network/networkd-dhcp4.c +++ b/src/network/networkd-dhcp4.c @@ -842,6 +842,12 @@ static int dhcp4_update_address(Link *link, assert(netmask); assert(lifetime); + /* address_handler calls link_request_set_routes() and link_request_set_nexthop(). Before they + * are called, the related flags must be cleared. Otherwise, the link becomes configured state + * before routes are configured. */ + link->static_routes_configured = false; + link->static_nexthops_configured = false; + prefixlen = in4_addr_netmask_to_prefixlen(netmask); r = address_new(&addr); diff --git a/src/network/networkd-dhcp6.c b/src/network/networkd-dhcp6.c index 70be2d6da7..f21dd29ec1 100644 --- a/src/network/networkd-dhcp6.c +++ b/src/network/networkd-dhcp6.c @@ -596,7 +596,6 @@ static int dhcp6_lease_address_acquired(sd_dhcp6_client *client, Link *link) { struct in6_addr ip6_addr; uint32_t lifetime_preferred, lifetime_valid; - link->dhcp6_address_configured = false; r = sd_dhcp6_client_get_lease(client, &lease); @@ -618,6 +617,11 @@ static int dhcp6_lease_address_acquired(sd_dhcp6_client *client, Link *link) { return link_request_set_routes(link); } else { log_link_debug(link, "Setting DHCPv6 addresses"); + /* address_handler calls link_request_set_routes() and link_request_set_nexthop(). + * Before they are called, the related flags must be cleared. Otherwise, the link + * becomes configured state before routes are configured. */ + link->static_routes_configured = false; + link->static_nexthops_configured = false; link_set_state(link, LINK_STATE_CONFIGURING); } @@ -1118,6 +1122,11 @@ static int dhcp6_assign_delegated_prefix(Link *link, address->cinfo.ifa_prefered = lifetime_preferred; address->cinfo.ifa_valid = lifetime_valid; + /* address_handler calls link_request_set_routes() and link_request_set_nexthop(). Before they + * are called, the related flags must be cleared. Otherwise, the link becomes configured state + * before routes are configured. */ + link->static_routes_configured = false; + link->static_nexthops_configured = false; link->dhcp6_pd_address_configured = false; link_set_state(link, LINK_STATE_CONFIGURING); diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 4c16255a75..3949f88a22 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -976,6 +976,8 @@ static int link_request_set_nexthop(Link *link) { NextHop *nh; int r; + link->static_nexthops_configured = false; + LIST_FOREACH(nexthops, nh, link->network->static_nexthops) { r = nexthop_configure(nh, link, nexthop_handler); if (r < 0) @@ -1018,7 +1020,7 @@ static int route_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { if (link->route_messages == 0) { log_link_debug(link, "Routes set"); link->static_routes_configured = true; - link_check_ready(link); + link_request_set_nexthop(link); } return 1; @@ -1040,7 +1042,6 @@ int link_request_set_routes(Link *link) { assert(link->state != _LINK_STATE_INVALID); link->static_routes_configured = false; - link->static_routes_ready = false; if (!link_has_carrier(link) && !link->network->configure_without_carrier) /* During configuring addresses, the link lost its carrier. As networkd is dropping @@ -1069,7 +1070,7 @@ int link_request_set_routes(Link *link) { if (link->route_messages == 0) { link->static_routes_configured = true; - link_check_ready(link); + link_request_set_nexthop(link); } else { log_link_debug(link, "Setting routes"); link_set_state(link, LINK_STATE_CONFIGURING); @@ -1126,15 +1127,6 @@ void link_check_ready(Link *link) { return; } - if (!link->static_routes_ready) { - link->static_routes_ready = true; - r = link_request_set_nexthop(link); - if (r < 0) - link_enter_failed(link); - log_link_debug(link, "%s(): static routes are configured. Configuring static nexthops.", __func__); - return; - } - if (!link->static_nexthops_configured) { log_link_debug(link, "%s(): static nexthops are not configured.", __func__); return; @@ -1291,7 +1283,6 @@ static int link_request_set_addresses(Link *link) { link->addresses_ready = false; link->neighbors_configured = false; link->static_routes_configured = false; - link->static_routes_ready = false; link->static_nexthops_configured = false; link->routing_policy_rules_configured = false; diff --git a/src/network/networkd-link.h b/src/network/networkd-link.h index d0340b9719..5e5e1c8335 100644 --- a/src/network/networkd-link.h +++ b/src/network/networkd-link.h @@ -124,7 +124,6 @@ typedef struct Link { bool addresses_ready:1; bool neighbors_configured:1; bool static_routes_configured:1; - bool static_routes_ready:1; bool static_nexthops_configured:1; bool routing_policy_rules_configured:1; bool tc_configured:1; diff --git a/src/network/networkd-ndisc.c b/src/network/networkd-ndisc.c index ac5b242fc1..62392d37b6 100644 --- a/src/network/networkd-ndisc.c +++ b/src/network/networkd-ndisc.c @@ -818,9 +818,16 @@ static void ndisc_handler(sd_ndisc *nd, sd_ndisc_event event, sd_ndisc_router *r if (link->ndisc_addresses_messages == 0) link->ndisc_addresses_configured = true; - else + else { log_link_debug(link, "Setting SLAAC addresses."); + /* address_handler calls link_request_set_routes() and link_request_set_nexthop(). + * Before they are called, the related flags must be cleared. Otherwise, the link + * becomes configured state before routes are configured. */ + link->static_routes_configured = false; + link->static_nexthops_configured = false; + } + if (link->ndisc_routes_messages == 0) link->ndisc_routes_configured = true; else From 5d976f5f64a29e9df0afe95724716eb9c4221b24 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Tue, 14 Jul 2020 12:48:02 +0900 Subject: [PATCH 13/16] network: do not call link_check_ready() in link_request_set_routing_policy_rule() It will be called in link_request_set_nexthop() or serveral handlers(). --- src/network/networkd-link.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 3949f88a22..91ec959011 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -932,10 +932,9 @@ static int link_request_set_routing_policy_rule(Link *link) { } routing_policy_rule_purge(link->manager, link); - if (link->routing_policy_rule_messages == 0) { + if (link->routing_policy_rule_messages == 0) link->routing_policy_rules_configured = true; - link_check_ready(link); - } else { + else { log_link_debug(link, "Setting routing policy rules"); link_set_state(link, LINK_STATE_CONFIGURING); } From 6906794dd1698954b349ec3ec84f1494ecd63cd3 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Wed, 15 Jul 2020 01:30:09 +0900 Subject: [PATCH 14/16] network: dhcp4: do not assign new address before old one is not removed If DHCP4 client lost a lease, and then soon acquire new lease, then the removal of the old address may not be completed. If that happens, and the new and old addresses are the same, then the new address will be considered as a foreign address. Such a situation can occur when the DHCP4 server is restarted. This makes networkd wait for the removal of the old address when a new lease is acquired. This also makes the link in configuring state when renewing address. --- src/network/networkd-dhcp4.c | 387 ++++++++++++++++++++++------------- src/network/networkd-link.h | 1 + 2 files changed, 241 insertions(+), 147 deletions(-) diff --git a/src/network/networkd-dhcp4.c b/src/network/networkd-dhcp4.c index 38cf3f287b..bad7970e2b 100644 --- a/src/network/networkd-dhcp4.c +++ b/src/network/networkd-dhcp4.c @@ -20,12 +20,12 @@ #include "sysctl-util.h" #include "web-util.h" -static int dhcp_remove_routes(Link *link, sd_dhcp_lease *lease, const struct in_addr *address, bool remove_all); -static int dhcp_remove_router(Link *link, sd_dhcp_lease *lease, const struct in_addr *address, bool remove_all); -static int dhcp_remove_dns_routes(Link *link, sd_dhcp_lease *lease, const struct in_addr *address, bool remove_all); +static int dhcp_remove_routes(Link *link, sd_dhcp_lease *lease, const struct in_addr *address, bool remove_all, link_netlink_message_handler_t callback); +static int dhcp_remove_router(Link *link, sd_dhcp_lease *lease, const struct in_addr *address, bool remove_all, link_netlink_message_handler_t callback); +static int dhcp_remove_dns_routes(Link *link, sd_dhcp_lease *lease, const struct in_addr *address, bool remove_all, link_netlink_message_handler_t callback); static int dhcp_remove_address(Link *link, sd_dhcp_lease *lease, const struct in_addr *address, link_netlink_message_handler_t callback); -static int dhcp_remove_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link); -static int dhcp_lease_renew(sd_dhcp_client *client, Link *link); +static int dhcp4_update_address(Link *link, bool announce); +static int dhcp4_remove_all(Link *link); void dhcp4_release_old_lease(Link *link) { struct in_addr address = {}, address_old = {}; @@ -40,9 +40,9 @@ void dhcp4_release_old_lease(Link *link) { (void) sd_dhcp_lease_get_address(link->dhcp_lease_old, &address_old); (void) sd_dhcp_lease_get_address(link->dhcp_lease, &address); - (void) dhcp_remove_routes(link, link->dhcp_lease_old, &address_old, false); - (void) dhcp_remove_router(link, link->dhcp_lease_old, &address_old, false); - (void) dhcp_remove_dns_routes(link, link->dhcp_lease_old, &address_old, false); + (void) dhcp_remove_routes(link, link->dhcp_lease_old, &address_old, false, NULL); + (void) dhcp_remove_router(link, link->dhcp_lease_old, &address_old, false, NULL); + (void) dhcp_remove_dns_routes(link, link->dhcp_lease_old, &address_old, false, NULL); if (!in4_addr_equal(&address_old, &address)) (void) dhcp_remove_address(link, link->dhcp_lease_old, &address_old, NULL); @@ -88,17 +88,12 @@ static int dhcp4_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *li if (link->dhcp4_messages == 0) { if (link->dhcp4_route_failed) { - struct in_addr address = {}; - link->dhcp4_route_failed = false; link->dhcp4_route_retrying = true; - (void) sd_dhcp_lease_get_address(link->dhcp_lease, &address); - (void) dhcp_remove_routes(link, link->dhcp_lease, &address, true); - (void) dhcp_remove_router(link, link->dhcp_lease, &address, true); - (void) dhcp_remove_dns_routes(link, link->dhcp_lease, &address, true); - (void) dhcp_remove_address(link, link->dhcp_lease, &address, dhcp_remove_address_handler); - + r = dhcp4_remove_all(link); + if (r < 0) + link_enter_failed(link); return 1; } if (!link->network->dhcp_send_decline) @@ -177,7 +172,7 @@ static int link_set_dns_routes(Link *link, const struct in_addr *address) { r = route_new(&route); if (r < 0) - return log_link_error_errno(link, r, "Could not allocate route: %m"); + return log_link_error_errno(link, r, "Could not allocate route: %m"); /* Set routes to DNS servers. */ @@ -266,7 +261,7 @@ static int link_set_dhcp_routes(Link *link) { r = dhcp_prefix_route_from_lease(link->dhcp_lease, table, &address, &prefix_route); if (r < 0) - return log_link_error_errno(link, r, "Could not create prefix route: %m"); + return log_link_error_errno(link, r, "Could not create prefix route: %m"); r = dhcp_route_configure(&prefix_route, link); if (r < 0) @@ -344,7 +339,7 @@ static int link_set_dhcp_routes(Link *link) { r = route_new(&route_gw); if (r < 0) - return log_link_error_errno(link, r, "Could not allocate route: %m"); + return log_link_error_errno(link, r, "Could not allocate route: %m"); /* The dhcp netmask may mask out the gateway. Add an explicit * route for the gw host so that we can route no matter the @@ -401,7 +396,26 @@ static int link_set_dhcp_routes(Link *link) { return link_set_dns_routes(link, &address); } -static int dhcp_remove_routes(Link *link, sd_dhcp_lease *lease, const struct in_addr *address, bool remove_all) { +static int dhcp_route_remove(Route *route, Link *link, link_netlink_message_handler_t callback) { + int r; + + r = route_remove(route, link, callback); + if (r < 0) + return r; + + if (callback) + link->dhcp4_remove_messages++; + + return 0; +} + +static int dhcp_remove_routes( + Link *link, + sd_dhcp_lease *lease, + const struct in_addr *address, + bool remove_all, + link_netlink_message_handler_t callback) { + _cleanup_free_ sd_dhcp_route **routes = NULL; uint32_t table; int n, i, r; @@ -440,13 +454,21 @@ static int dhcp_remove_routes(Link *link, sd_dhcp_lease *lease, const struct in_ if (!remove_all && set_contains(link->dhcp_routes, route)) continue; - (void) route_remove(route, link, NULL); + r = dhcp_route_remove(route, link, callback); + if (r < 0) + return r; } return n; } -static int dhcp_remove_router(Link *link, sd_dhcp_lease *lease, const struct in_addr *address, bool remove_all) { +static int dhcp_remove_router( + Link *link, + sd_dhcp_lease *lease, + const struct in_addr *address, + bool remove_all, + link_netlink_message_handler_t callback) { + _cleanup_(route_freep) Route *route_gw = NULL, *route = NULL; const struct in_addr *router; uint32_t table; @@ -484,8 +506,11 @@ static int dhcp_remove_router(Link *link, sd_dhcp_lease *lease, const struct in_ route_gw->priority = link->network->dhcp_route_metric; route_gw->table = table; - if (remove_all || !set_contains(link->dhcp_routes, route_gw)) - (void) route_remove(route_gw, link, NULL); + if (remove_all || !set_contains(link->dhcp_routes, route_gw)) { + r = dhcp_route_remove(route_gw, link, callback); + if (r < 0) + return r; + } r = route_new(&route); if (r < 0) @@ -498,8 +523,11 @@ static int dhcp_remove_router(Link *link, sd_dhcp_lease *lease, const struct in_ route->priority = link->network->dhcp_route_metric; route->table = table; - if (remove_all || !set_contains(link->dhcp_routes, route)) - (void) route_remove(route, link, NULL); + if (remove_all || !set_contains(link->dhcp_routes, route)) { + r = dhcp_route_remove(route, link, callback); + if (r < 0) + return r; + } Route *rt; LIST_FOREACH(routes, rt, link->network->static_routes) { @@ -512,13 +540,21 @@ static int dhcp_remove_router(Link *link, sd_dhcp_lease *lease, const struct in_ if (!remove_all && in4_addr_equal(router, &rt->gw.in)) continue; - (void) route_remove(rt, link, NULL); + r = dhcp_route_remove(rt, link, callback); + if (r < 0) + return r; } return 0; } -static int dhcp_remove_dns_routes(Link *link, sd_dhcp_lease *lease, const struct in_addr *address, bool remove_all) { +static int dhcp_remove_dns_routes( + Link *link, + sd_dhcp_lease *lease, + const struct in_addr *address, + bool remove_all, + link_netlink_message_handler_t callback) { + const struct in_addr *dns; uint32_t table; int i, n, r; @@ -544,7 +580,7 @@ static int dhcp_remove_dns_routes(Link *link, sd_dhcp_lease *lease, const struct r = route_new(&route); if (r < 0) - return log_link_error_errno(link, r, "Could not allocate route: %m"); + return log_link_error_errno(link, r, "Could not allocate route: %m"); route->family = AF_INET; route->dst.in = dns[i]; @@ -558,7 +594,9 @@ static int dhcp_remove_dns_routes(Link *link, sd_dhcp_lease *lease, const struct if (!remove_all && set_contains(link->dhcp_routes, route)) continue; - (void) route_remove(route, link, NULL); + r = dhcp_route_remove(route, link, callback); + if (r < 0) + return r; } if (!link_prefixroute(link)) { @@ -566,36 +604,18 @@ static int dhcp_remove_dns_routes(Link *link, sd_dhcp_lease *lease, const struct r = dhcp_prefix_route_from_lease(lease, table, address, &prefix_route); if (r < 0) - return log_link_warning_errno(link, r, "Could not delete prefix route: %m"); + return log_link_warning_errno(link, r, "Could not create prefix route: %m"); - if (remove_all || !set_contains(link->dhcp_routes, prefix_route)) - (void) route_remove(prefix_route, link, NULL); + if (remove_all || !set_contains(link->dhcp_routes, prefix_route)) { + r = dhcp_route_remove(prefix_route, link, callback); + if (r < 0) + return r; + } } return 0; } -static int dhcp_remove_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { - int r; - - assert(link); - - /* This is only used when retrying to assign the address received from DHCPv4 server. - * See dhcp4_route_handler(). */ - - if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) - return 1; - - r = sd_netlink_message_get_errno(m); - if (r < 0) - log_link_message_warning_errno(link, m, r, "Failed to remove DHCPv4 address, ignoring"); - else - (void) manager_rtnl_process_address(rtnl, m, link->manager); - - (void) dhcp_lease_renew(link->dhcp_client, link); - return 1; -} - static int dhcp_remove_address( Link *link, sd_dhcp_lease *lease, const struct in_addr *address, @@ -621,7 +641,12 @@ static int dhcp_remove_address( if (sd_dhcp_lease_get_netmask(lease, &netmask) >= 0) a->prefixlen = in4_addr_netmask_to_prefixlen(&netmask); - (void) address_remove(a, link, callback); + r = address_remove(a, link, callback); + if (r < 0) + return r; + + if (callback) + link->dhcp4_remove_messages++; return 0; } @@ -676,8 +701,90 @@ static int dhcp_reset_hostname(Link *link) { return 0; } +static int dhcp4_remove_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { + int r; + + assert(m); + assert(link); + assert(link->dhcp4_remove_messages > 0); + + link->dhcp4_remove_messages--; + + if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) + return 1; + + r = sd_netlink_message_get_errno(m); + if (r < 0 && r != -ESRCH) + log_link_message_warning_errno(link, m, r, "Failed to remove DHCPv4 route, ignoring"); + + if (link->dhcp4_remove_messages == 0) { + r = dhcp4_update_address(link, false); + if (r < 0) + link_enter_failed(link); + } + + return 1; +} + +static int dhcp4_remove_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { + int r; + + assert(m); + assert(link); + assert(link->dhcp4_remove_messages > 0); + + link->dhcp4_remove_messages--; + + if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) + return 1; + + r = sd_netlink_message_get_errno(m); + if (r < 0 && r != -EADDRNOTAVAIL) + log_link_message_warning_errno(link, m, r, "Failed to remove DHCPv4 address, ignoring"); + else + (void) manager_rtnl_process_address(rtnl, m, link->manager); + + if (link->dhcp4_remove_messages == 0) { + r = dhcp4_update_address(link, false); + if (r < 0) + link_enter_failed(link); + } + + return 1; +} + +static int dhcp4_remove_all(Link *link) { + struct in_addr address; + int r; + + assert(link); + assert(link->dhcp_lease); + + r = sd_dhcp_lease_get_address(link->dhcp_lease, &address); + if (r < 0) + return log_link_error_errno(link, r, "Failed to get DHCPv4 address: %m"); + + r = dhcp_remove_routes(link, link->dhcp_lease, &address, true, dhcp4_remove_route_handler); + if (r < 0) + return r; + + r = dhcp_remove_router(link, link->dhcp_lease, &address, true, dhcp4_remove_route_handler); + if (r < 0) + return r; + + r = dhcp_remove_dns_routes(link, link->dhcp_lease, &address, true, dhcp4_remove_route_handler); + if (r < 0) + return r; + + r = dhcp_remove_address(link, link->dhcp_lease, &address, dhcp4_remove_address_handler); + if (r < 0) + return r; + + return 0; +} + static int dhcp_lease_lost(Link *link) { - struct in_addr address = {}; + int r; assert(link); assert(link->dhcp_lease); @@ -686,13 +793,17 @@ static int dhcp_lease_lost(Link *link) { link->dhcp4_configured = false; - (void) sd_dhcp_lease_get_address(link->dhcp_lease, &address); - (void) dhcp_remove_routes(link, link->dhcp_lease, &address, true); - (void) dhcp_remove_router(link, link->dhcp_lease, &address, true); - (void) dhcp_remove_dns_routes(link, link->dhcp_lease, &address, true); - (void) dhcp_remove_address(link, link->dhcp_lease, &address, NULL); - (void) dhcp_reset_mtu(link); - (void) dhcp_reset_hostname(link); + r = dhcp4_remove_all(link); + if (r < 0) + return r; + + r = dhcp_reset_mtu(link); + if (r < 0) + return r; + + r = dhcp_reset_hostname(link); + if (r < 0) + return r; link->dhcp_lease = sd_dhcp_lease_unref(link->dhcp_lease); link_dirty(link); @@ -830,17 +941,21 @@ static int dhcp4_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link * return 1; } -static int dhcp4_update_address(Link *link, - struct in_addr *address, - struct in_addr *netmask, - uint32_t lifetime) { +static int dhcp4_update_address(Link *link, bool announce) { _cleanup_(address_freep) Address *addr = NULL; + uint32_t lifetime = CACHE_INFO_INFINITY_LIFE_TIME; + struct in_addr address, netmask; unsigned prefixlen; int r; - assert(address); - assert(netmask); - assert(lifetime); + assert(link); + assert(link->network); + + if (!link->dhcp_lease) + return 0; + + link_set_state(link, LINK_STATE_CONFIGURING); + link->dhcp4_configured = false; /* address_handler calls link_request_set_routes() and link_request_set_nexthop(). Before they * are called, the related flags must be cleared. Otherwise, the link becomes configured state @@ -848,18 +963,59 @@ static int dhcp4_update_address(Link *link, link->static_routes_configured = false; link->static_nexthops_configured = false; - prefixlen = in4_addr_netmask_to_prefixlen(netmask); + r = sd_dhcp_lease_get_address(link->dhcp_lease, &address); + if (r < 0) + return log_link_warning_errno(link, r, "DHCP error: no address: %m"); + + r = sd_dhcp_lease_get_netmask(link->dhcp_lease, &netmask); + if (r < 0) + return log_link_warning_errno(link, r, "DHCP error: no netmask: %m"); + + if (!FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_DHCP)) { + r = sd_dhcp_lease_get_lifetime(link->dhcp_lease, &lifetime); + if (r < 0) + return log_link_warning_errno(link, r, "DHCP error: no lifetime: %m"); + } + + prefixlen = in4_addr_netmask_to_prefixlen(&netmask); + + if (announce) { + const struct in_addr *router; + + r = sd_dhcp_lease_get_router(link->dhcp_lease, &router); + if (r < 0 && r != -ENODATA) + return log_link_error_errno(link, r, "DHCP error: Could not get gateway: %m"); + + if (r > 0 && !in4_addr_is_null(&router[0])) + log_struct(LOG_INFO, + LOG_LINK_INTERFACE(link), + LOG_LINK_MESSAGE(link, "DHCPv4 address %u.%u.%u.%u/%u via %u.%u.%u.%u", + ADDRESS_FMT_VAL(address), + prefixlen, + ADDRESS_FMT_VAL(router[0])), + "ADDRESS=%u.%u.%u.%u", ADDRESS_FMT_VAL(address), + "PREFIXLEN=%u", prefixlen, + "GATEWAY=%u.%u.%u.%u", ADDRESS_FMT_VAL(router[0])); + else + log_struct(LOG_INFO, + LOG_LINK_INTERFACE(link), + LOG_LINK_MESSAGE(link, "DHCPv4 address %u.%u.%u.%u/%u", + ADDRESS_FMT_VAL(address), + prefixlen), + "ADDRESS=%u.%u.%u.%u", ADDRESS_FMT_VAL(address), + "PREFIXLEN=%u", prefixlen); + } r = address_new(&addr); if (r < 0) - return r; + return log_oom(); addr->family = AF_INET; - addr->in_addr.in.s_addr = address->s_addr; + addr->in_addr.in.s_addr = address.s_addr; addr->cinfo.ifa_prefered = lifetime; addr->cinfo.ifa_valid = lifetime; addr->prefixlen = prefixlen; - addr->broadcast.s_addr = address->s_addr | ~netmask->s_addr; + addr->broadcast.s_addr = address.s_addr | ~netmask.s_addr; addr->prefix_route = link_prefixroute(link); /* allow reusing an existing address and simply update its lifetime @@ -873,102 +1029,34 @@ static int dhcp4_update_address(Link *link, static int dhcp_lease_renew(sd_dhcp_client *client, Link *link) { sd_dhcp_lease *lease; - struct in_addr address; - struct in_addr netmask; - uint32_t lifetime = CACHE_INFO_INFINITY_LIFE_TIME; int r; assert(link); assert(client); - assert(link->network); r = sd_dhcp_client_get_lease(client, &lease); if (r < 0) return log_link_warning_errno(link, r, "DHCP error: no lease: %m"); sd_dhcp_lease_unref(link->dhcp_lease); - link->dhcp4_configured = false; link->dhcp_lease = sd_dhcp_lease_ref(lease); link_dirty(link); - r = sd_dhcp_lease_get_address(lease, &address); - if (r < 0) - return log_link_warning_errno(link, r, "DHCP error: no address: %m"); - - r = sd_dhcp_lease_get_netmask(lease, &netmask); - if (r < 0) - return log_link_warning_errno(link, r, "DHCP error: no netmask: %m"); - - if (!FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_DHCP)) { - r = sd_dhcp_lease_get_lifetime(link->dhcp_lease, &lifetime); - if (r < 0) - return log_link_warning_errno(link, r, "DHCP error: no lifetime: %m"); - } - - r = dhcp4_update_address(link, &address, &netmask, lifetime); - if (r < 0) - return log_link_warning_errno(link, r, "Could not update IP address: %m"); - - return 0; + return dhcp4_update_address(link, false); } static int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) { - const struct in_addr *router; sd_dhcp_lease *lease; - struct in_addr address; - struct in_addr netmask; - unsigned prefixlen; - uint32_t lifetime = CACHE_INFO_INFINITY_LIFE_TIME; int r; assert(client); assert(link); - link->dhcp4_configured = false; - r = sd_dhcp_client_get_lease(client, &lease); if (r < 0) return log_link_error_errno(link, r, "DHCP error: No lease: %m"); - r = sd_dhcp_lease_get_address(lease, &address); - if (r < 0) - return log_link_error_errno(link, r, "DHCP error: No address: %m"); - - r = sd_dhcp_lease_get_netmask(lease, &netmask); - if (r < 0) - return log_link_error_errno(link, r, "DHCP error: No netmask: %m"); - - prefixlen = in4_addr_netmask_to_prefixlen(&netmask); - - if (!FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_DHCP)) { - r = sd_dhcp_lease_get_lifetime(lease, &lifetime); - if (r < 0) - return log_link_warning_errno(link, r, "DHCP error: no lifetime: %m"); - } - - r = sd_dhcp_lease_get_router(lease, &router); - if (r < 0 && r != -ENODATA) - return log_link_error_errno(link, r, "DHCP error: Could not get gateway: %m"); - - if (r > 0 && !in4_addr_is_null(&router[0])) - log_struct(LOG_INFO, - LOG_LINK_INTERFACE(link), - LOG_LINK_MESSAGE(link, "DHCPv4 address %u.%u.%u.%u/%u via %u.%u.%u.%u", - ADDRESS_FMT_VAL(address), - prefixlen, - ADDRESS_FMT_VAL(router[0])), - "ADDRESS=%u.%u.%u.%u", ADDRESS_FMT_VAL(address), - "PREFIXLEN=%u", prefixlen, - "GATEWAY=%u.%u.%u.%u", ADDRESS_FMT_VAL(router[0])); - else - log_struct(LOG_INFO, - LOG_LINK_INTERFACE(link), - LOG_LINK_MESSAGE(link, "DHCPv4 address %u.%u.%u.%u/%u", - ADDRESS_FMT_VAL(address), - prefixlen), - "ADDRESS=%u.%u.%u.%u", ADDRESS_FMT_VAL(address), - "PREFIXLEN=%u", prefixlen); - + sd_dhcp_lease_unref(link->dhcp_lease); link->dhcp_lease = sd_dhcp_lease_ref(lease); link_dirty(link); @@ -1019,9 +1107,14 @@ static int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) { } } - r = dhcp4_update_address(link, &address, &netmask, lifetime); - if (r < 0) - return log_link_warning_errno(link, r, "Could not update IP address: %m"); + if (link->dhcp4_remove_messages == 0) { + r = dhcp4_update_address(link, true); + if (r < 0) + return r; + } else + log_link_debug(link, + "The link has previously assigned DHCPv4 address or routes. " + "The newly assigned address and routes will set up after old ones are removed."); return 0; } diff --git a/src/network/networkd-link.h b/src/network/networkd-link.h index 5e5e1c8335..7b39dd91ae 100644 --- a/src/network/networkd-link.h +++ b/src/network/networkd-link.h @@ -100,6 +100,7 @@ typedef struct Link { char *lease_file; uint32_t original_mtu; unsigned dhcp4_messages; + unsigned dhcp4_remove_messages; unsigned dhcp6_address_messages; unsigned dhcp6_route_messages; unsigned dhcp6_pd_address_messages; From 93b0b88c3a3f9e942aeedcdf5d12585dba61790d Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Wed, 15 Jul 2020 02:00:06 +0900 Subject: [PATCH 15/16] network: free address when it is removed --- src/network/networkd-address.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/network/networkd-address.c b/src/network/networkd-address.c index 44e317e990..aeadb7b01b 100644 --- a/src/network/networkd-address.c +++ b/src/network/networkd-address.c @@ -444,6 +444,8 @@ static int address_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, Link r = sd_netlink_message_get_errno(m); if (r < 0 && r != -EADDRNOTAVAIL) log_link_message_warning_errno(link, m, r, "Could not drop address"); + else + (void) manager_rtnl_process_address(rtnl, m, link->manager); return 1; } From 43bf28741f0273f9722c52e2fd37049355e04186 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Wed, 15 Jul 2020 03:40:26 +0900 Subject: [PATCH 16/16] network: drop doubled white space --- src/network/netdev/bond.c | 2 +- src/network/netdev/bridge.c | 2 +- src/network/networkctl.c | 2 +- src/network/networkd-network.c | 2 +- src/network/tc/tc-util.c | 4 ++-- src/network/wait-online/manager.c | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/network/netdev/bond.c b/src/network/netdev/bond.c index 8c1ba11e5f..4d61c217b1 100644 --- a/src/network/netdev/bond.c +++ b/src/network/netdev/bond.c @@ -288,7 +288,7 @@ int link_set_bond(Link *link) { r = netlink_call_async(link->manager->rtnl, NULL, req, link_set_bond_handler, link_netlink_destroy_callback, link); if (r < 0) - return log_link_error_errno(link, r, "Could not send rtnetlink message: %m"); + return log_link_error_errno(link, r, "Could not send rtnetlink message: %m"); link_ref(link); diff --git a/src/network/netdev/bridge.c b/src/network/netdev/bridge.c index de492c5eeb..ef5a9bb694 100644 --- a/src/network/netdev/bridge.c +++ b/src/network/netdev/bridge.c @@ -218,7 +218,7 @@ int link_set_bridge(Link *link) { return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_FAST_LEAVE attribute: %m"); } - if (link->network->allow_port_to_be_root >= 0) { + if (link->network->allow_port_to_be_root >= 0) { r = sd_netlink_message_append_u8(req, IFLA_BRPORT_PROTECT, link->network->allow_port_to_be_root); if (r < 0) return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_PROTECT attribute: %m"); diff --git a/src/network/networkctl.c b/src/network/networkctl.c index cc4639aeaf..a80a6185da 100644 --- a/src/network/networkctl.c +++ b/src/network/networkctl.c @@ -1662,7 +1662,7 @@ static int link_status_one( r = table_add_many(table, TABLE_EMPTY, TABLE_STRING, "Mode:", - TABLE_STRING, bond_mode_to_string(info->mode), + TABLE_STRING, bond_mode_to_string(info->mode), TABLE_EMPTY, TABLE_STRING, "Miimon:", TABLE_TIMESPAN_MSEC, jiffies_to_usec(info->miimon), diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c index 22bd06a891..f7021f3edb 100644 --- a/src/network/networkd-network.c +++ b/src/network/networkd-network.c @@ -52,7 +52,7 @@ void network_apply_anonymize_if_set(Network *network) { /* RFC7844 section 3.6.: The client intending to protect its privacy SHOULD only request a minimal number of options in the PRL and SHOULD also randomly shuffle - the ordering of option codes in the PRL. If this random ordering + the ordering of option codes in the PRL. If this random ordering cannot be implemented, the client MAY order the option codes in the PRL by option code number (lowest to highest). */ diff --git a/src/network/tc/tc-util.c b/src/network/tc/tc-util.c index 5f25acbdd6..8a5afeab2d 100644 --- a/src/network/tc/tc-util.c +++ b/src/network/tc/tc-util.c @@ -26,7 +26,7 @@ int tc_init(double *ret_ticks_in_usec, uint32_t *ret_hz) { if (r < 4) return -EIO; - clock_factor = (double) clock_resolution / USEC_PER_SEC; + clock_factor = (double) clock_resolution / USEC_PER_SEC; ticks_in_usec = (double) ticks_to_usec / usec_to_ticks * clock_factor; } @@ -57,7 +57,7 @@ int tc_time_to_tick(usec_t t, uint32_t *ret) { return 0; } -int parse_tc_percent(const char *s, uint32_t *percent) { +int parse_tc_percent(const char *s, uint32_t *percent) { int r; assert(s); diff --git a/src/network/wait-online/manager.c b/src/network/wait-online/manager.c index 40a29f19aa..6ab26d3ca9 100644 --- a/src/network/wait-online/manager.c +++ b/src/network/wait-online/manager.c @@ -323,7 +323,7 @@ int manager_new(Manager **ret, Hashmap *interfaces, char **ignore, if (r < 0) return r; - (void) sd_event_add_signal(m->event, NULL, SIGTERM, NULL, NULL); + (void) sd_event_add_signal(m->event, NULL, SIGTERM, NULL, NULL); (void) sd_event_add_signal(m->event, NULL, SIGINT, NULL, NULL); if (timeout > 0) {