]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
networkd: auto promote links if "promote_secondaries" is unset (#7167)
authorMichael Vogt <michael.vogt@gmail.com>
Fri, 24 Nov 2017 20:03:05 +0000 (21:03 +0100)
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Fri, 24 Nov 2017 20:03:05 +0000 (21:03 +0100)
The DHCP code in systemd-networkd relies on the
`net.ipv4.conf.{default,all,<if>}.promote_secondaries` sysctl to be set
(the kernels default is that it is unset). If this sysctl is not set
DHCP will work most of the time, however when the IP address changes
between leases then the system will loose its IP.

Because some distributions decided to not ship these defaults (Debian
is an example and via downstream Ubuntu) networkd by default will now
enable this sysctl opton automatically.

src/network/networkd-dhcp4.c
src/network/networkd-link.c
src/network/networkd-link.h

index 6e3f6629b60c21e12d56c76a1f41ce38cb7bd39f..cacd867f9b006529ad9aff155d4497895183e79e 100644 (file)
 #include "alloc-util.h"
 #include "dhcp-lease-internal.h"
 #include "hostname-util.h"
+#include "parse-util.h"
 #include "netdev/vrf.h"
 #include "network-internal.h"
 #include "networkd-link.h"
 #include "networkd-manager.h"
 #include "networkd-network.h"
+#include "string-util.h"
+#include "sysctl-util.h"
 
 static int dhcp4_route_handler(sd_netlink *rtnl, sd_netlink_message *m,
                                void *userdata) {
@@ -586,6 +589,58 @@ static int dhcp4_set_hostname(Link *link) {
         return sd_dhcp_client_set_hostname(link->dhcp_client, hn);
 }
 
+static bool promote_secondaries_enabled(const char *ifname) {
+        char *promote_secondaries_sysctl, *promote_secondaries_path;
+        int r;
+
+        promote_secondaries_path = strjoina("net/ipv4/conf/", ifname, "/promote_secondaries");
+        r = sysctl_read(promote_secondaries_path, &promote_secondaries_sysctl);
+        if (r < 0) {
+                log_debug_errno(r, "Cannot read sysctl %s", promote_secondaries_path);
+                return false;
+        }
+
+        truncate_nl(promote_secondaries_sysctl);
+        r = parse_boolean(promote_secondaries_sysctl);
+        if (r < 0)
+                log_warning_errno(r, "Cannot parse sysctl %s with content %s as boolean", promote_secondaries_path, promote_secondaries_sysctl);
+        return r > 0;
+}
+
+/* dhcp4_set_promote_secondaries will ensure this interface has
+ * the "promote_secondaries" option in the kernel set. If this sysctl
+ * is not set DHCP will work only as long as the IP address does not
+ * changes between leases. The kernel will remove all secondary IP
+ * addresses of an interface otherwise. The way systemd-network works
+ * is that the new IP of a lease is added as a secondary IP and when
+ * the primary one expires it relies on the kernel to promote the
+ * secondary IP. See also https://github.com/systemd/systemd/issues/7163
+ */
+int dhcp4_set_promote_secondaries(Link *link) {
+        int r;
+
+        assert(link);
+        assert(link->network);
+        assert(link->network->dhcp & ADDRESS_FAMILY_IPV4);
+
+        /* check if the kernel has promote_secondaries enabled for our
+         * interface. If it is not globally enabled or enabled for the
+         * specific interface we must either enable it.
+         */
+        if (!(promote_secondaries_enabled("all") || promote_secondaries_enabled("default") || promote_secondaries_enabled(link->ifname))) {
+                char *promote_secondaries_path = NULL;
+
+                log_link_debug(link, "promote_secondaries is unset, setting it");
+                promote_secondaries_path = strjoina("net/ipv4/conf/", link->ifname, "/promote_secondaries");
+                r = sysctl_write(promote_secondaries_path, "1");
+                if (r < 0)
+                        log_link_warning_errno(link, r, "cannot set sysctl %s to 1", promote_secondaries_path);
+                return r > 0;
+        }
+
+        return 0;
+}
+
 int dhcp4_configure(Link *link) {
         int r;
 
index e68b83be0077dfb72741a00e7b4b1c178f2f7a39..9b342b14f6c3a9863d0ef1b8b5e9a09692a2f743 100644 (file)
@@ -2621,6 +2621,10 @@ static int link_configure(Link *link) {
         }
 
         if (link_dhcp4_enabled(link)) {
+                r = dhcp4_set_promote_secondaries(link);
+                if (r < 0)
+                        return r;
+
                 r = dhcp4_configure(link);
                 if (r < 0)
                         return r;
index bffe865f0136aaa59abe199e4f8596347692235a..a05a788d7844c891bfe803a8beb1375a74c0e295 100644 (file)
@@ -169,6 +169,7 @@ int link_set_mtu(Link *link, uint32_t mtu);
 
 int ipv4ll_configure(Link *link);
 int dhcp4_configure(Link *link);
+int dhcp4_set_promote_secondaries(Link *link);
 int dhcp6_configure(Link *link);
 int dhcp6_request_address(Link *link, int ir);