=== MTU considerations When running OsmoGGSN, the user may want to take network Maximum Transmission Unit (MTU) into consideration, and configure it based on network specific setup. Applying and announcing a proper MTU provides, for the MS employing it, reduced transmission overhead (ie. due to IP fragmentation) and avoids potential problems due to misconfigured nodes in the path (e.g. ICMP packet filtering). In OsmoGGSN, the MTU can be configured per APN through the VTY, see <>. If told so by the config, osmo-ggsn will apply the MTU on the APN network interface. ==== MTU announced to MS The configured MTU is also announced to the MS through: * IPv4 APN: GTPv1C Create PDP Context Response, PCO IE "IPv4 Link MTU", 3GPP TS 24.008 Table 10.5.154. * IPv6 APN: ICMPv6 Routing Advertisement during IPv6 SLAAC procedure, RFC 4861. NOTE: It is up to the MS to request and use the link MTU size provided by the network. Hence, providing an MTU size does not guarantee that there will be no packets larger than the provided value. ==== GTP-U tunnel overhead OsmoGGSN is encapsulating traffic over GTP-U, it means the packets being received, encapsulated and transmitted over the tunnel get their size increased by the sum of IP/UDP/GTPv1U headers being prepended: * IP: IPv4 headers can take up to 60 bytes (due to IPv4 options). IPv6 headers can take up to 40 bytes (assuming no extension headers for IPv6 in general, since they are uncommon). Hence, the 60 bytes of IPv4 are picked since that's greater than the IPv4. * UDP: The UDP header takes 8 bytes. * GTPv1U: The GTPv1U header takes 12 bytes, assuming here no extensions headers are used (OsmoGGSN doesn't use them). Hence, these headers add an overhead of up to `80`` bytes, as per the below formula: ---- GTPv1U_OVERHEAD = 60 + 8 + 12 = 80 bytes ---- ==== Figuring out optimal MTU value There is no golden MTU value, since it really depends on the local (and remote) networks where traffic is routed. The idea is finding out a value that: * Is as big as possible, to avoid need to split big chunks of data into lots of small packets, hence affecting performance due to processing overhead: extra headers being trnasmitted, plus processing of extra packets. * Is small enough so that it can be transported over the lower layers of the links involving the communication, avoiding IP fragmentation, which again hurts performance. OsmoGGSN, by default, assumes that traffic is transported over an Ethernet network, which has a standarized maximum MTU of 1500 bytes. Hence, by default it announces an MTU of of `1420` bytes as per the following formula: ---- TUNNEL_MTU = ETH_MTU - GTPv1U_OVERHEAD = 1500 - 80 = 1420 bytes ---- Under certain networks, the base MTU may already be smaller than Ethernet's MTU (1500 bytes), due to, for instance, existence of some sort of extra tunneling protocol in the path, such as a VPN, ipsec, extra VLAN levels, etc. Under this scenario, the user must take care of figuring out the new base MTU value to use for the calculations presented above. This can be accomplished by packet inspection (eg. `wireshark`) or with tools such as `ping`, running it with a certain packet size and the IPv4 DF bit set, and see up to which packet size the networks is able to forward the message. .Example: Test if packets of 1420 bytes can reach peer host 176.16.222.4 ---- $ ping -M probe 176.16.222.4 -s 1420 ---- === Increasing outer MTU Specifications at IEEE 802.3 establish that standard Ethernet has a maximum MTU of `1500` bytes. However, many Ethernet controllers can nowadays overcome this limit and allow the use of so called _jumbo frames_. The _jumbo frames_ maximum MTU varies depending on the implementation, with `9000` bytes being a commonly used limit. Note that using MTUs over the standarized `1500` bytes by means of _jumbo frames_ can create interoperability problems with networks not supporting such frames (eg. forcing of IP packet fragmentation), plus the fact that larger frames consume more Ethernet link transmission time, causing greater delays and increasing latency. Nevertheless, if the operator: * is in control of the whole GTP-U path between OsmoGGSN and the MS, and * has Ethernet NICs supporting MTUs bigger than 1500 or uses any other link layer supporting as well bigger MTUs. Then, it may be wise for the operator to configure such links with an increased outer MTU so that they can end up transporting GTP-U inner payload of 1500 bytes without fragmentation ocurring. Hence, following the examples presented on the above sections, one could configure *all the links* which are part of the GTP-U path to use an outer MTU of `1580` bytes, as per the following formula: ---- TUNNEL_MTU = ETH_MTU + GTPv1U_OVERHEAD = 1500 + 80 = 1580 bytes ---- .Example: Setting an MTU of `1580` to network interface `eth0` under Linux ---- ip link set mtu 1580 dev eth0 ---- ==== TCP MSS Clamping Usually endpoints use Path MTU Discovery (PMTUD) to determine the maximum MTU to reach the peer. However, this technique may sometimes not be optimal for all users of OsmoGGSN: * MS may not support requesting and/or configuring the MTU OsmoGGSN announced. * MS may not support PMTUD on its network stack, or may not have it enabled or may be buggy. * Network may be misconfigured or some middlebox may be buggy (eg. not forwarding ICMP `Packet Too Big` packets). Furthermore, PMTUD takes time to figure out the maximum MTU to use, since it relies on sending data and checking if it got lost, and adapting to the fact, reducing efficiency (throughput) of connections or even stalling them completely when big packets are generated. Hence, it may become useful for the operator of OsmoGGSN to, on top of MTU configuration, also configure its network to tune TCP Maximum Segment Size (MSS) option of TCP connections being established over the GTPv1U tunnel. This will make sure at least TCP connections can use the full capacity of the path MTU without passing its imit. The MSS TCP option is an optional parameter in the TCP header sent during TCP initial handshake (`SYN,SYN/ACK`) that specifies the maximum amount of bytes of TCP payload a TCP chunk may transport. The MSS value doesn't count the underlaying IP/TCP headers. Hence, following up on MTU size calculations from previous section, with a sample GTPv1U MTU of 1420 bytes and IP header of 60 bytes, plus taking into account that TCP header can span up to 56 bytes, we'd get to an MSS value of: ---- MSS = TUNNEL_MTU - IP_HDR - TCP_HDR = 1420 - 60 - 56 = 1304 ---- In linux, the MSS of TCP connections can be clamped using nftables: ---- nft 'add rule ip nat prerouting iifname "apn0" tcp flags syn / syn,rst counter tcp option maxseg size set 1304' nft 'insert rule ip nat postrouting oifname "apn0" tcp flags syn / syn,rst counter tcp option maxseg size set 1304' nft 'add rule ip6 nat prerouting iifname "apn0" tcp flags syn / syn,rst counter tcp option maxseg size set 1304' nft 'insert rule ip6 nat postrouting oifname "apn0" tcp flags syn / syn,rst counter tcp option maxseg size set 1304' ---- ==== Further Reading Check the following specs regarding MTU in 3GPP mobile networks: * 3GPP TS 29.061 section 11.2.1.5 * 3GPP TS 290.060 section 13.2 IP Fragmentation * 3GPP TS 25.414 section 6.1.3.3 * 3GPP TS 23.060 section 9.3, Annex C * 3GPP TS 24.008 (PCO IPv4 MTU) * RFC 4861 (IPv6 Router Advertisement)