]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/network/networkd-link.c
Merge pull request #12753 from jrouleau/fix/hibernate-resume-timeout
[thirdparty/systemd.git] / src / network / networkd-link.c
index 6613992a091f5fe043a7c24d676dc568f9f1498b..67c0903fa69b834b4344652a0c5939ee80ce497c 100644 (file)
@@ -62,6 +62,20 @@ DUID* link_get_duid(Link *link) {
                 return &link->manager->duid;
 }
 
+int link_sysctl_ipv6_enabled(Link *link) {
+        _cleanup_free_ char *value = NULL;
+        int r;
+
+        r = sysctl_read_ip_property(AF_INET6, link->ifname, "disable_ipv6", &value);
+        if (r < 0)
+                return log_link_warning_errno(link, r,
+                                              "Failed to read net.ipv6.conf.%s.disable_ipv6 sysctl property: %m",
+                                              link->ifname);
+
+        link->sysctl_ipv6_enabled = value[0] == '0';
+        return link->sysctl_ipv6_enabled;
+}
+
 static bool link_dhcp6_enabled(Link *link) {
         assert(link);
 
@@ -80,7 +94,7 @@ static bool link_dhcp6_enabled(Link *link) {
         if (STRPTR_IN_SET(link->kind, "can", "vcan", "vxcan"))
                 return false;
 
-        if (manager_sysctl_ipv6_enabled(link->manager) == 0)
+        if (link_sysctl_ipv6_enabled(link) == 0)
                 return false;
 
         return link->network->dhcp & ADDRESS_FAMILY_IPV6;
@@ -166,7 +180,7 @@ static bool link_ipv6ll_enabled(Link *link) {
         if (link->network->bond)
                 return false;
 
-        if (manager_sysctl_ipv6_enabled(link->manager) == 0)
+        if (link_sysctl_ipv6_enabled(link) == 0)
                 return false;
 
         return link->network->link_local & ADDRESS_FAMILY_IPV6;
@@ -181,7 +195,7 @@ static bool link_ipv6_enabled(Link *link) {
         if (link->network->bond)
                 return false;
 
-        if (manager_sysctl_ipv6_enabled(link->manager) == 0)
+        if (link_sysctl_ipv6_enabled(link) == 0)
                 return false;
 
         if (STRPTR_IN_SET(link->kind, "can", "vcan", "vxcan"))
@@ -230,7 +244,7 @@ static bool link_ipv6_forward_enabled(Link *link) {
         if (link->network->ip_forward == _ADDRESS_FAMILY_BOOLEAN_INVALID)
                 return false;
 
-        if (manager_sysctl_ipv6_enabled(link->manager) == 0)
+        if (link_sysctl_ipv6_enabled(link) == 0)
                 return false;
 
         return link->network->ip_forward & ADDRESS_FAMILY_IPV6;
@@ -541,6 +555,7 @@ static int link_new(Manager *manager, sd_netlink_message *message, Link **ret) {
                 .rtnl_extended_attrs = true,
                 .ifindex = ifindex,
                 .iftype = iftype,
+                .sysctl_ipv6_enabled = -1,
         };
 
         link->ifname = strdup(ifname);
@@ -680,14 +695,17 @@ static void link_enter_unmanaged(Link *link) {
         link_dirty(link);
 }
 
-int link_stop_clients(Link *link) {
+int link_stop_clients(Link *link, bool may_keep_dhcp) {
         int r = 0, k;
 
         assert(link);
         assert(link->manager);
         assert(link->manager->event);
 
-        if (link->dhcp_client) {
+        dhcp4_release_old_lease(link);
+
+        if (link->dhcp_client && (!may_keep_dhcp || !link->network ||
+                                  !FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_DHCP_ON_STOP))) {
                 k = sd_dhcp_client_stop(link->dhcp_client);
                 if (k < 0)
                         r = log_link_warning_errno(link, k, "Could not stop DHCPv4 client: %m");
@@ -731,7 +749,7 @@ void link_enter_failed(Link *link) {
 
         link_set_state(link, LINK_STATE_FAILED);
 
-        link_stop_clients(link);
+        link_stop_clients(link, false);
 
         link_dirty(link);
 }
@@ -829,14 +847,14 @@ static int link_request_set_routing_policy_rule(Link *link) {
                         continue;
                 }
 
-                r = routing_policy_rule_configure(rule, link, NULL, false);
+                r = routing_policy_rule_configure(rule, link, NULL);
                 if (r < 0) {
                         log_link_warning_errno(link, r, "Could not set routing policy rules: %m");
                         link_enter_failed(link);
                         return r;
                 }
-
-                link->routing_policy_rule_messages++;
+                if (r > 0)
+                        link->routing_policy_rule_messages++;
         }
 
         routing_policy_rule_purge(link->manager, link);
@@ -910,8 +928,8 @@ int link_request_set_routes(Link *link) {
                                 link_enter_failed(link);
                                 return r;
                         }
-
-                        link->route_messages++;
+                        if (r > 0)
+                                link->route_messages++;
                 }
 
         if (link->route_messages == 0) {
@@ -957,23 +975,26 @@ void link_check_ready(Link *link) {
         if (!link->routing_policy_rules_configured)
                 return;
 
-        if (link_ipv4ll_enabled(link, ADDRESS_FAMILY_IPV4) && !(link->ipv4ll_address && link->ipv4ll_route))
-                return;
+        if (link_has_carrier(link) || !link->network->configure_without_carrier) {
 
-        if (link_ipv6ll_enabled(link) &&
-            in_addr_is_null(AF_INET6, (const union in_addr_union*) &link->ipv6ll_address))
-                return;
+                if (link_ipv4ll_enabled(link, ADDRESS_FAMILY_IPV4) && !(link->ipv4ll_address && link->ipv4ll_route))
+                        return;
 
-        if ((link_dhcp4_enabled(link) || link_dhcp6_enabled(link)) &&
-            !link->dhcp4_configured &&
-            !link->dhcp6_configured &&
-            !(link_ipv4ll_enabled(link, ADDRESS_FAMILY_FALLBACK_IPV4) && link->ipv4ll_address && link->ipv4ll_route))
-                /* When DHCP is enabled, at least one protocol must provide an address, or
-                 * an IPv4ll fallback address must be configured. */
-                return;
+                if (link_ipv6ll_enabled(link) &&
+                    in_addr_is_null(AF_INET6, (const union in_addr_union*) &link->ipv6ll_address))
+                        return;
 
-        if (link_ipv6_accept_ra_enabled(link) && !link->ndisc_configured)
-                return;
+                if ((link_dhcp4_enabled(link) || link_dhcp6_enabled(link)) &&
+                    !link->dhcp4_configured &&
+                    !link->dhcp6_configured &&
+                    !(link_ipv4ll_enabled(link, ADDRESS_FAMILY_FALLBACK_IPV4) && link->ipv4ll_address && link->ipv4ll_route))
+                        /* When DHCP is enabled, at least one protocol must provide an address, or
+                         * an IPv4ll fallback address must be configured. */
+                        return;
+
+                if (link_ipv6_accept_ra_enabled(link) && !link->ndisc_configured)
+                        return;
+        }
 
         if (link->state != LINK_STATE_CONFIGURED)
                 link_enter_configured(link);
@@ -1191,8 +1212,8 @@ static int link_request_set_addresses(Link *link) {
                         link_enter_failed(link);
                         return r;
                 }
-
-                link->address_messages++;
+                if (r > 0)
+                        link->address_messages++;
         }
 
         LIST_FOREACH(labels, label, link->network->address_labels) {
@@ -2485,6 +2506,33 @@ static bool link_is_static_route_configured(Link *link, Route *route) {
         return false;
 }
 
+static bool link_address_is_dynamic(Link *link, Address *address) {
+        Route *route;
+        Iterator i;
+
+        assert(link);
+        assert(address);
+
+        if (address->cinfo.ifa_prefered != CACHE_INFO_INFINITY_LIFE_TIME)
+                return true;
+
+        /* Even when the address is leased from a DHCP server, networkd assign the address
+         * without lifetime when KeepConfiguration=dhcp. So, let's check that we have
+         * corresponding routes with RTPROT_DHCP. */
+        SET_FOREACH(route, link->routes_foreign, i) {
+                if (route->protocol != RTPROT_DHCP)
+                        continue;
+
+                if (address->family != route->family)
+                        continue;
+
+                if (in_addr_equal(address->family, &address->in_addr, &route->prefsrc))
+                        return true;
+        }
+
+        return false;
+}
+
 static int link_drop_foreign_config(Link *link) {
         Address *address;
         Route *route;
@@ -2496,6 +2544,12 @@ static int link_drop_foreign_config(Link *link) {
                 if (address->family == AF_INET6 && in_addr_is_link_local(AF_INET6, &address->in_addr) == 1)
                         continue;
 
+                if (link_address_is_dynamic(link, address)) {
+                        if (FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_DHCP))
+                                continue;
+                } else if (FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_STATIC))
+                        continue;
+
                 if (link_is_static_address_configured(link, address)) {
                         r = address_add(link, address->family, &address->in_addr, address->prefixlen, NULL);
                         if (r < 0)
@@ -2512,6 +2566,14 @@ static int link_drop_foreign_config(Link *link) {
                 if (route->protocol == RTPROT_KERNEL)
                         continue;
 
+                if (route->protocol == RTPROT_STATIC &&
+                    FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_STATIC))
+                        continue;
+
+                if (route->protocol == RTPROT_DHCP &&
+                    FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_DHCP))
+                        continue;
+
                 if (link_is_static_route_configured(link, route)) {
                         r = route_add(link, route->family, &route->dst, route->dst_prefixlen, route->tos, route->priority, route->table, NULL);
                         if (r < 0)
@@ -2578,7 +2640,8 @@ static int link_configure(Link *link) {
 
         /* Drop foreign config, but ignore loopback or critical devices.
          * We do not want to remove loopback address or addresses used for root NFS. */
-        if (!(link->flags & IFF_LOOPBACK) && !(link->network->dhcp_critical)) {
+        if (!(link->flags & IFF_LOOPBACK) &&
+            link->network->keep_configuration != KEEP_CONFIGURATION_YES) {
                 r = link_drop_foreign_config(link);
                 if (r < 0)
                         return r;
@@ -3264,7 +3327,7 @@ static int link_carrier_lost(Link *link) {
         if (link->setting_mtu)
                 return 0;
 
-        r = link_stop_clients(link);
+        r = link_stop_clients(link, false);
         if (r < 0) {
                 link_enter_failed(link);
                 return r;