]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
networkd: bump MTU to 1280 for interfaces which have IPv6 enabled (#3077)
authorSusant Sahani <ssahani@users.noreply.github.com>
Thu, 21 Apr 2016 00:34:13 +0000 (06:04 +0530)
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Thu, 21 Apr 2016 00:34:13 +0000 (20:34 -0400)
IPv6 protocol requires a minimum MTU of 1280 bytes on the interface.
This fixes #3046.

Introduce helper link_ipv6_enabled() to figure out whether IPV6 is enabled.
Introduce network_has_static_ipv6_addresses() to find out if any static
ipv6 address configured.
If IPv6 is not configured on any interface that is SLAAC, DHCPv6 and static
IPv6 addresses not configured, then IPv6 will be automatically disabled for that
interface, that is we write "1" to /proc/sys/net/ipv6/conf//disable_ipv6.

man/systemd.network.xml
src/basic/missing.h
src/network/networkd-link.c
src/network/networkd-network.c
src/network/networkd-network.h

index d7947836e9b2a1f566c5280b6937b7b5d857c206..8ae384185d3f5f549377fa5f31fe29d96d1133e4 100644 (file)
           <para>The maximum transmission unit in bytes to set for the
           device. The usual suffixes K, M, G, are supported and are
           understood to the base of 1024.</para>
+          <para>Note that if IPv6 is enabled on the interface, and the MTU is chosen
+          below 1280 (the minimum MTU for IPv6) it will automatically be increased to this value.</para>
         </listitem>
       </varlistentry>
       <varlistentry>
           <para>Identity Association Identifier for the interface, a 32-bit unsigned integer.</para>
         </listitem>
       </varlistentry>
+      <varlistentry>
+      <listitem>
+        <para>Note that an interface without any static IPv6 addresses configured, and neither
+        DHCPv6 nor IPv6LL enabled, shall be considered to have no IPv6 support. IPv6 will be
+        automatically disabled for that interface by writing "1" to
+        <filename>/proc/sys/net/ipv6/conf/<replaceable>ifname</replaceable>/disable_ipv6.</filename>
+        </para>
+      </listitem>
+      </varlistentry>
     </variablelist>
   </refsect1>
 
index 6a49ccd28109c3a643c237a55ec15e5707d93bc5..6616f0b7205f9115ebae11e186f20f6ec8ccbdc1 100644 (file)
@@ -828,6 +828,10 @@ struct btrfs_ioctl_quota_ctl_args {
 #define IPV6_UNICAST_IF 76
 #endif
 
+#ifndef IPV6_MIN_MTU
+#define IPV6_MIN_MTU 1280
+#endif
+
 #ifndef IFF_MULTI_QUEUE
 #define IFF_MULTI_QUEUE 0x100
 #endif
index 9059a68fe358838b0afa2366b8c916b96e91d629..0fb3aa6c43831f2f40e354de1194c39614d8c52b 100644 (file)
@@ -99,6 +99,15 @@ static bool link_ipv6ll_enabled(Link *link) {
         return link->network->link_local & ADDRESS_FAMILY_IPV6;
 }
 
+static bool link_ipv6_enabled(Link *link) {
+        assert(link);
+
+        if (!socket_ipv6_is_supported())
+                return false;
+
+        return link_dhcp6_enabled(link) || link_ipv6ll_enabled(link) || network_has_static_ipv6_addresses(link->network);
+}
+
 static bool link_lldp_rx_enabled(Link *link) {
         assert(link);
 
@@ -218,6 +227,31 @@ static IPv6PrivacyExtensions link_ipv6_privacy_extensions(Link *link) {
         return link->network->ipv6_privacy_extensions;
 }
 
+static int link_enable_ipv6(Link *link) {
+        const char *p = NULL;
+        bool disabled;
+        int r;
+
+        if (link->flags & IFF_LOOPBACK)
+                return 0;
+
+        disabled = !link_ipv6_enabled(link);
+
+        p = strjoina("/proc/sys/net/ipv6/conf/", link->ifname, "/disable_ipv6");
+
+        r = write_string_file(p, one_zero(disabled), WRITE_STRING_FILE_VERIFY_ON_FAILURE);
+        if (r < 0)
+                log_link_warning_errno(link, r, "Cannot %s IPv6 for interface %s: %m", disabled ? "disable" : "enable", link->ifname);
+        else {
+                if (disabled)
+                        log_link_info(link, "IPv6 disabled for interface: %m");
+                else
+                        log_link_info(link, "IPv6 enabled for interface: %m");
+        }
+
+        return 0;
+}
+
 void link_update_operstate(Link *link) {
         LinkOperationalState operstate;
         assert(link);
@@ -1510,7 +1544,21 @@ static int link_up(Link *link) {
                         return log_link_error_errno(link, r, "Could not set MAC address: %m");
         }
 
+        /* If IPv6 not configured (no static IPv6 address and neither DHCPv6 nor IPv6LL is enabled)
+           for this interface then disable IPv6 else enable it. */
+        (void) link_enable_ipv6(link);
+
         if (link->network->mtu) {
+                /* IPv6 protocol requires a minimum MTU of IPV6_MTU_MIN(1280) bytes
+                   on the interface. Bump up MTU bytes to IPV6_MTU_MIN. */
+                if (link_ipv6_enabled(link) && link->network->mtu < IPV6_MIN_MTU) {
+
+                        log_link_warning(link, "Bumping MTU to " STRINGIFY(IPV6_MIN_MTU) ", as "
+                                         "IPv6 is requested and requires a minimum MTU of " STRINGIFY(IPV6_MIN_MTU) " bytes: %m");
+
+                        link->network->mtu = IPV6_MIN_MTU;
+                }
+
                 r = sd_netlink_message_append_u32(req, IFLA_MTU, link->network->mtu);
                 if (r < 0)
                         return log_link_error_errno(link, r, "Could not set MTU: %m");
@@ -1520,7 +1568,7 @@ static int link_up(Link *link) {
         if (r < 0)
                 return log_link_error_errno(link, r, "Could not open IFLA_AF_SPEC container: %m");
 
-        if (socket_ipv6_is_supported()) {
+        if (link_ipv6_enabled(link)) {
                 /* if the kernel lacks ipv6 support setting IFF_UP fails if any ipv6 options are passed */
                 r = sd_netlink_message_open_container(req, AF_INET6);
                 if (r < 0)
index 1c7adf5180dd7f7f77678b690676049fdee148b9..07f8fb028f1fb8df2021c38dd9e240146c4a0f7c 100644 (file)
@@ -399,6 +399,19 @@ int network_apply(Manager *manager, Network *network, Link *link) {
         return 0;
 }
 
+bool network_has_static_ipv6_addresses(Network *network) {
+        Address *address;
+
+        assert(network);
+
+        LIST_FOREACH(addresses, address, network->static_addresses) {
+                if (address->family == AF_INET6)
+                        return true;
+        }
+
+        return false;
+}
+
 int config_parse_netdev(const char *unit,
                 const char *filename,
                 unsigned line,
index 3d44113b05bf4e057bda77a558614ed1ac64bddc..15417f48280f00ef3ab2eaced79b1691143dad79 100644 (file)
@@ -186,6 +186,8 @@ int network_get_by_name(Manager *manager, const char *name, Network **ret);
 int network_get(Manager *manager, struct udev_device *device, const char *ifname, const struct ether_addr *mac, Network **ret);
 int network_apply(Manager *manager, Network *network, Link *link);
 
+bool network_has_static_ipv6_addresses(Network *network);
+
 int config_parse_netdev(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
 int config_parse_domains(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
 int config_parse_tunnel(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);