From b67e8a4e3ede0447d54eca96399b3d5f81dfaecd Mon Sep 17 00:00:00 2001 From: Yuxiang Zhu Date: Thu, 29 Jun 2023 18:11:52 +0800 Subject: [PATCH] network: Add `IgnoreDdontFragment=` option for Fragmentation control (#28131) From `ip-link(8)`: > [no]ignore-df - enables/disables IPv4 DF suppression on this tunnel. Normally datagrams that exceed the MTU will be fragmented; the presence of the DF flag inhibits this, resulting instead in an ICMP Unreachable (Fragmentation Required) message. Enabling this attribute causes the DF flag to be ignored. If this option is enabled for a GRE/GRETAP tunnel, the `DF` flag in the outer IP header will not inherit the inner IP header's `DF` flag. This is useful to transfer packets that exceed the MTU of the underlay network. --- man/systemd.netdev.xml | 14 +++++++++++++- src/network/netdev/netdev-gperf.gperf | 3 ++- src/network/netdev/tunnel.c | 11 ++++++++++- src/network/netdev/tunnel.h | 3 ++- test/test-network/conf/25-erspan0-tunnel.netdev | 1 + test/test-network/conf/25-gretap-tunnel.netdev | 1 + test/test-network/systemd-networkd-tests.py | 4 ++++ 7 files changed, 33 insertions(+), 4 deletions(-) diff --git a/man/systemd.netdev.xml b/man/systemd.netdev.xml index ed765e1b9c..5b5536df90 100644 --- a/man/systemd.netdev.xml +++ b/man/systemd.netdev.xml @@ -1220,7 +1220,19 @@ DiscoverPathMTU= Takes a boolean. When true, enables Path MTU Discovery on - the tunnel. + the tunnel. + When IgnoreDontFragment= is enabled, + defaults to false. Otherwise, defaults to true. + + + + IgnoreDontFragment= + + Takes a boolean. When true, enables IPv4 Don't Fragment (DF) suppression on + the tunnel. Defaults to false. + Note that if IgnoreDontFragment= is set to true, + DiscoverPathMTU= cannot be set to true. + Only applicable to GRE, GRETAP, and ERSPAN tunnels. diff --git a/src/network/netdev/netdev-gperf.gperf b/src/network/netdev/netdev-gperf.gperf index ade5b1b919..d5aa522de8 100644 --- a/src/network/netdev/netdev-gperf.gperf +++ b/src/network/netdev/netdev-gperf.gperf @@ -77,7 +77,8 @@ Tunnel.TTL, config_parse_unsigned, Tunnel.Key, config_parse_tunnel_key, 0, offsetof(Tunnel, key) Tunnel.InputKey, config_parse_tunnel_key, 0, offsetof(Tunnel, ikey) Tunnel.OutputKey, config_parse_tunnel_key, 0, offsetof(Tunnel, okey) -Tunnel.DiscoverPathMTU, config_parse_bool, 0, offsetof(Tunnel, pmtudisc) +Tunnel.DiscoverPathMTU, config_parse_tristate, 0, offsetof(Tunnel, pmtudisc) +Tunnel.IgnoreDontFragment, config_parse_bool, 0, offsetof(Tunnel, ignore_df) Tunnel.Mode, config_parse_ip6tnl_mode, 0, offsetof(Tunnel, ip6tnl_mode) Tunnel.IPv6FlowLabel, config_parse_ipv6_flowlabel, 0, 0 Tunnel.CopyDSCP, config_parse_bool, 0, offsetof(Tunnel, copy_dscp) diff --git a/src/network/netdev/tunnel.c b/src/network/netdev/tunnel.c index 2addfeecaa..881be3c405 100644 --- a/src/network/netdev/tunnel.c +++ b/src/network/netdev/tunnel.c @@ -378,6 +378,10 @@ static int netdev_gre_erspan_fill_message_create(NetDev *netdev, Link *link, sd_ if (r < 0) return r; + r = sd_netlink_message_append_u8(m, IFLA_GRE_IGNORE_DF, t->ignore_df); + if (r < 0) + return r; + if (t->key != 0) { ikey = okey = htobe32(t->key); iflags |= GRE_KEY; @@ -746,6 +750,11 @@ static int netdev_tunnel_verify(NetDev *netdev, const char *filename) { "The local address cannot be '%s' when Independent= or AssignToLoopback= is enabled, ignoring.", strna(netdev_local_address_type_to_string(t->local_type))); + if (t->pmtudisc > 0 && t->ignore_df) + return log_netdev_error_errno(netdev, SYNTHETIC_ERRNO(EINVAL), + "IgnoreDontFragment= cannot be enabled when DiscoverPathMTU= is enabled"); + if (t->pmtudisc < 0) + t->pmtudisc = !t->ignore_df; return 0; } @@ -1189,7 +1198,7 @@ static void netdev_tunnel_init(NetDev *netdev) { assert(t); t->local_type = _NETDEV_LOCAL_ADDRESS_TYPE_INVALID; - t->pmtudisc = true; + t->pmtudisc = -1; t->fou_encap_type = NETDEV_FOO_OVER_UDP_ENCAP_DIRECT; t->isatap = -1; t->gre_erspan_sequence = -1; diff --git a/src/network/netdev/tunnel.h b/src/network/netdev/tunnel.h index 7c81f22391..713f2fbf37 100644 --- a/src/network/netdev/tunnel.h +++ b/src/network/netdev/tunnel.h @@ -54,7 +54,8 @@ typedef struct Tunnel { Ip6TnlMode ip6tnl_mode; FooOverUDPEncapType fou_encap_type; - bool pmtudisc; + int pmtudisc; + bool ignore_df; bool copy_dscp; bool independent; bool fou_tunnel; diff --git a/test/test-network/conf/25-erspan0-tunnel.netdev b/test/test-network/conf/25-erspan0-tunnel.netdev index ee295d901f..0ed03803a6 100644 --- a/test/test-network/conf/25-erspan0-tunnel.netdev +++ b/test/test-network/conf/25-erspan0-tunnel.netdev @@ -13,3 +13,4 @@ Local = 172.16.1.200 Remote = 172.16.1.100 Key=101 SerializeTunneledPackets=true +IgnoreDontFragment=true diff --git a/test/test-network/conf/25-gretap-tunnel.netdev b/test/test-network/conf/25-gretap-tunnel.netdev index 86ac3f7c5b..af5ea2fb2b 100644 --- a/test/test-network/conf/25-gretap-tunnel.netdev +++ b/test/test-network/conf/25-gretap-tunnel.netdev @@ -8,3 +8,4 @@ Local=10.65.223.238 Remote=10.65.223.239 Key=106 SerializeTunneledPackets=true +IgnoreDontFragment=true diff --git a/test/test-network/systemd-networkd-tests.py b/test/test-network/systemd-networkd-tests.py index b5ef83a9c0..c068f37a8a 100755 --- a/test/test-network/systemd-networkd-tests.py +++ b/test/test-network/systemd-networkd-tests.py @@ -1796,6 +1796,8 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities): self.assertRegex(output, 'okey 0.0.0.106') self.assertRegex(output, 'iseq') self.assertRegex(output, 'oseq') + self.assertIn('nopmtudisc', output) + self.assertIn('ignore-df', output) output = check_output('ip -d link show gretap98') print(output) self.assertRegex(output, 'gretap remote 10.65.223.239 local any dev dummy98') @@ -1955,6 +1957,8 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities): self.assertNotIn('erspan_hwid 1f', output) self.assertIn('ikey 0.0.0.101', output) self.assertIn('iseq', output) + self.assertIn('nopmtudisc', output) + self.assertIn('ignore-df', output) output = check_output('ip -d link show erspan98') print(output) self.assertIn('erspan remote 172.16.1.100 local any', output)