]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/network/networkd-dhcp4.c
network/dhcp4: support IPv6 only mode (RFC 8925)
[thirdparty/systemd.git] / src / network / networkd-dhcp4.c
index 3e8038ede6b71ea648d0530f6526350b42cc21a7..57d40e856ee0c4309721026f6ca80bbf730992ff 100644 (file)
@@ -1452,6 +1452,16 @@ static bool link_needs_dhcp_broadcast(Link *link) {
         return r == true;
 }
 
+static bool link_dhcp4_ipv6_only_mode(Link *link) {
+        assert(link);
+        assert(link->network);
+
+        if (link->network->dhcp_ipv6_only_mode >= 0)
+                return link->network->dhcp_ipv6_only_mode;
+
+        return link_dhcp6_enabled(link) || link_ipv6_accept_ra_enabled(link);
+}
+
 static int dhcp4_configure(Link *link) {
         sd_dhcp_option *send_option;
         void *request_options;
@@ -1560,6 +1570,12 @@ static int dhcp4_configure(Link *link) {
                                 return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set request flag for 6rd: %m");
                 }
 
+                if (link_dhcp4_ipv6_only_mode(link)) {
+                        r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_IPV6_ONLY_PREFERRED);
+                        if (r < 0)
+                                return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set request flag for IPv6-only preferred option: %m");
+                }
+
                 SET_FOREACH(request_options, link->network->dhcp_request_options) {
                         uint32_t option = PTR_TO_UINT32(request_options);
 
@@ -1668,7 +1684,7 @@ int dhcp4_update_mac(Link *link) {
                 return r;
 
         if (restart) {
-                r = sd_dhcp_client_start(link->dhcp_client);
+                r = dhcp4_start(link);
                 if (r < 0)
                         return r;
         }
@@ -1676,10 +1692,35 @@ int dhcp4_update_mac(Link *link) {
         return 0;
 }
 
-int dhcp4_start(Link *link) {
+int dhcp4_update_ipv6_connectivity(Link *link) {
+        assert(link);
+
+        if (!link->network)
+                return 0;
+
+        if (!link->network->dhcp_ipv6_only_mode)
+                return 0;
+
+        if (!link->dhcp_client)
+                return 0;
+
+        /* If the client is running, set the current connectivity. */
+        if (sd_dhcp_client_is_running(link->dhcp_client))
+                return sd_dhcp_client_set_ipv6_connectivity(link->dhcp_client, link_has_ipv6_connectivity(link));
+
+        /* If the client has been already stopped or not started yet, let's check the current connectivity
+         * and start the client if necessary. */
+        if (link_has_ipv6_connectivity(link))
+                return 0;
+
+        return dhcp4_start_full(link, /* set_ipv6_connectivity = */ false);
+}
+
+int dhcp4_start_full(Link *link, bool set_ipv6_connectivity) {
         int r;
 
         assert(link);
+        assert(link->network);
 
         if (!link->dhcp_client)
                 return 0;
@@ -1694,6 +1735,12 @@ int dhcp4_start(Link *link) {
         if (r < 0)
                 return r;
 
+        if (set_ipv6_connectivity) {
+                r = dhcp4_update_ipv6_connectivity(link);
+                if (r < 0)
+                        return r;
+        }
+
         return 1;
 }