Mazimum Transmission Unit (MTU) Frame Size in OS X

The approaches below use the pico editor, but any text editor will do.

A paper describing the SystemStarter process can be found at: http://www.usenix.org/events/bsdcon02/full_papers/sanchez/sanchez_html/

Determining correct MTU Size

MTU = maximum IP datagram that can be sent over an interface, including IP headers. This must be less than or equal to the maximum size data field of the lower layer (e.g., 1500 bytes for Ethernet).

One way to determine what MTU size to use is via the ping command. The general procedure is to send a ping with the “Don’t Fragment” bit set (-D option) to a host on the network using different size data fields (-s option).

ping -D -s n

where n is the ICMP data field size you want to use. The total IP packet size transmitted is “n + 28” bytes.

Start with a value of n=1472 (equivalent to MTU = 1500) and lower the values for n until you get a valid response to your ping. The MTU for that interface will then be “n + 28”.

Substitute a real host for “testhost” in the examples below.

In the following examples, I am connected to a Corporate network via VPN (using SOHO router) over en0.

For example, the following setting returns a “Message too long” error indicating that it is larger than the MTU supported on that interface (1500 + 28 = 1528):

$ ping -D -s 1500 testhost
PING testhost (x.x.x.x): 1500 data bytes
ping: sendto: Message too long
ping: sendto: Message too long
ping: sendto: Message too long
^C
--- testhost ping statistics ---
3 packets transmitted, 0 packets received, 100% packet loss

Then lower the value used for “-s” until you get one that works.

$ ping -D -s 1472  testhost
PING testhost (x.x.x.x): 1472 data bytes
36 bytes from usertest-dhcp.corporate.com (10.21.23.123): frag needed and DF set (MTU 1400)
Vr HL TOS  Len   ID Flg  off TTL Pro  cks      Src      Dst
 4  5  00 05dc de21   2 0000  3f  01 c0a5 10.116.44.139  x.x.x.x 

36 bytes from usertest-dhcp.corporate.com (10.21.23.123): frag needed and DF set (MTU 1400)
Vr HL TOS  Len   ID Flg  off TTL Pro  cks      Src      Dst
 4  5  00 05dc de22   2 0000  3f  01 c0a4 10.116.44.139  x.x.x.x 

^C
--- testhost ping statistics ---
2 packets transmitted, 0 packets received, 100% packet loss
$
$ ping -D -s 1372  testhost
PING testhost (x.x.x.x): 1372 data bytes
1380 bytes from x.x.x.x: icmp_seq=0 ttl=108 time=113.067 ms
1380 bytes from x.x.x.x: icmp_seq=1 ttl=108 time=113.713 ms
^C
--- testhost ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max/stddev = 113.067/113.390/113.713/0.323 ms
snoot:~ chsharp$

A Cisco 871 router is nice enough to return an ICMP “unreachable” message with a clue to the right MTU (1400). I just subtracted 28 from that value for my second try and verified that 1400 was the right MTU size.

Not all routers or networks will return this error. Sometimes the ping might just time out.

Also, be sure to ping a host that supports pinging and doesn’t have a firewall in front of it that blocks ICMP packets. 🙂

Approach 1

For those interested in a “click & forget about it” solution, Cocktail is a powerful OS X application for various purposes, including MTU adjustment:

 http://www.maintain.se/cocktail/index.php

Make sure to use the correct version of Cocktail for your OS X version.

Approach 2

This approach does not apply to OS X versions 10.4 and up. Apple got rid of the /System/Library/StartupItems/Network directory in 10.4.

This one is kind of easy and the approach involves changing startup items for the network settings upon bootup (on the system files). The file we can to change is located at:

/System/Library/StartupItems/Network

The file that we need to change is called Network.You are going to need to sudo edit the file to make the change. The command would be the following:

sudo pico Network

This will ask for your password and if you have admin rights to the system it will let you edit it. The file should look something like this:

#!/bin/sh##
# Configure network interfaces and host name
##

. /etc/rc.common

StartService ()
{
 ConsoleMessage "Initializing network"

 ipconfig waitall > /dev/null 2>&1

 if [ "${IPV6:=-YES-}" = "-NO-" ]
 then
 sysctl -w net.inet6.ip6.auto_on=0 > /dev/null
 ip6 -x
 fi

 if [ "${IPFORWARDING:=-NO-}" = "-YES-" ]
 then
 sysctl -w net.inet.ip.forwarding=1 > /dev/null
 else
 sysctl -w net.inet.ip.forwarding=0 > /dev/null
 fi
}

StopService ()
{
return 0
}

RestartService ()
{
return 0
}

RunService "$1"

We need to add to this file the change of MTU. To do this just look inside the StartService () function and at the end add the following:

ifconfig <interface> mtu 1400

The <interface> needs to be changed to the interface name you want to change. For a single interface system it usually is en0. For wireless it usually is en1. To know for sure you need to issue the command ifconfig that will tell you what interface you want to modify. Or you can just modify them all.

Once changed it would look like the following:

StartService ()
{

 ConsoleMessage "Initializing network"

 ipconfig waitall > /dev/null 2>&1

 if [ "${IPV6:=-YES-}" = "-NO-" ]

 then
 sysctl -w net.inet6.ip6.auto_on=0 > /dev/null
 ip6 -x
 fi

 if [ "${IPFORWARDING:=-NO-}" = "-YES-" ]
 then
 sysctl -w net.inet.ip.forwarding=1 > /dev/null
 else
 sysctl -w net.inet.ip.forwarding=0 > /dev/null
 fi

 ifconfig en2 mtu 1400

}

In this case we changed the configuration for en2 (a secondary nic card).

Once the system reboots it will issue the command and return the MTU to 1400. But any change state of the interface is going to cause the OS to reset it back to 1500 (man I hope they fix this soon).

Approach 3

This is a very nice way of doing it, and the one I would probably recommend. It is more elaborate but certainly makes life easier to enable or disable the change.

This information is taken from Apple support article 107474

Use the procedure below to create a startup item script that sets the maximum transmission unit (MTU) value for your network interface(s). This may be required when using certain Internet service providers.

Note: This document applies to Mac OS X 10.2 through 10.2.8. I have also tested this on OS X 10.4.8. (Update: Tested on 10.4.11 as well)

Important:

  • This document discusses an advanced procedure. If you are not familiar with command line interface and manual configuration in general, you should seek assistance. If you do not follow these steps precisely, the script may not work, which could prevent the computer from starting up normally.
  • AppleCare does not offer any type of free technical support on setting up or creating Startup Items. Contract based support for setting up and creating Startup Items, and creating shell scripts is only offered by Apple Professional Services. For more information on Apple Professions Services see (http://www.apple.com/services/ ).

Follow these steps to create a script that sets the MTU each time the computer restarts:

  1. Open Terminal (/Applications/Utilities/).
  2. Type: cd /Library
  3. Press Return.
  4. Type: mkdir StartupItems
  5. Press Return. (If you encounter an error, continue to step 6.)
  6. Type: cd StartupItems
  7. Press Return.
  8. Type: mkdir MTU
  9. Type: chmod 755 MTU
  10. Press Return.
  11. Type: cd MTU
  12. Press Return.
  13. Type: pico MTU
  14. Press Return.

In the pico editor, paste in the following text.

Begin copying below this line.

#!/bin/sh

. /etc/rc.common

##
# Configure a network interface MTU setting
##

# This script will set the MTU setting for the specified interface(s)
#
# The name of the interface (ex. en0) must be edited to match the interface
# to which the MTU setting should be applied
#
# The variable $MTU is set in the /etc/hostconfig file
#
##

StartService ()
{
ConsoleMessage "Configuring MTU"

### uncomment lines and change the value following 'mtu' as appropriate

if [ "${MTU:=-NO-}" = "-YES-" ]; then
# /sbin/ifconfig en0 mtu 1400
# /sbin/ifconfig en1 mtu 1400
fi
}

StopService ()
{
return 0
}

RestartService ()
{
return 0
}

RunService "$1"

End copying above this line.

  1. Uncomment the /sbin/ifconfig line(s) to set the MTU for a particular interface.

Note: Removing the number sign (#) from the beginning of a line uncomments it. Typically, en0 is the interface name for the Built-in Ethernet port and en1 is interface name for the AirPort Card. This is not always the case, though. To confirm that a network port is associated with a particular interface name, open the Network Utility (/Applications/Utilities/), and click the Info tab.

  1. When you have finished customizing the file, save it (press Control-O), press Return, and exit pico (press Control-X).
  2. Type: chmod 755 MTU
  3. Press Return.
  4. Type: pico StartupParameters.plist
  5. Press Return.
  6. In the pico editor paste in the following text for 10.4.8 (see farther down for 10.2.x).
  7. Begin copying below this line.
{
  Description     = "Set network MTU";
  Provides        = ("MTU");

# If you want the script to wait until the network is up and configured before
# running this script, then uncomment the following.

#    Requires = (Network, "Network Configuration"); 

}

If you are on OSX 10.2.x, paste this in instead:

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" </p>
<p>"http://www.apple.com/DTDs/PropertyList-1.0.dtd">

<plist version="1.0">

<dict>
  <key>Description</key>

  <string>Can set MTU</string>
  <key>OrderPreference</key>
  <string>None</string>
  <key>Provides</key>

  <array>

 <string>MTU</string>

 </array>

  <key>Requires</key>
  <array>

 <string>Network Configuration</string>
  </array>
</dict>
</plist>

End copying above this line.

  1. When you have finished customizing the file, save it (Control-O), press Return, and exit pico (Control-X).
  2. For OSX 10.4.8, type: chmod 644 StartupParameters.plist
  3. For OSX 10.2.x, type: chmod 755 StartupParameters.plist
  4. Press Return.
  5. Type: sudo pico /etc/hostconfig
  6. When prompted, enter your password.
  7. Press Return.
  8. In the pico editor, add this line at the bottom:
MTU=-YES-

Save it (Control-O), press Return, and exit pico (Control-X).

When you restart the computer, MTU is set for the interface that you specified.

Notes

The MTU will be reset after changing a Location, waking the computer from sleep, or changing the state of the network interface. To use the script again without having to restart, enter the following command:

sudo SystemStarter start MTU

If you experience any issues or wish to not set MTU during startup, you can turn off the new script by changing the MTU line in /etc/hostconfig to:

MTU=-NO-

Approach 4

Only for 10.4 and above. This method seems to work on 10.4.11.

Starting with Tiger (10.4), Apple started replacing the StartupItems with launchd for starting services. This migration continued in 10.5 (Leopard).

Launchd is missing a number of capabilities that were available when using StartupItems, such as specifying dependencies. Contributions are welcome to make this better.

Lingon is the editor I have used for managing launchd items.

Below is the non-Lingon version. I’ve continued to specify the pico editor, but any text editor will do (I normally use emacs). You can also use the Property List Editor to edit the plist if you want. Also, I’ve found that I have to use “sudo” to do most of this.

  1. Open Terminal (/Applications/Utilities/).
  2. Type: cd /Library
  3. Press Return.
  4. Type: sudo mkdir LaunchDaemons if it isn’t already there.
  5. Press Return. (If you encounter an error, continue to step 6.)
  6. Type: cd LaunchDaemons
  7. Press Return.
  8. Type: sudo pico com.xxxx.setmtu.plist. I use the convention com.chsharp.plist for the items that I create.
  9. Press Return.

In the pico editor, paste in the following text. You will need to modify it.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
        <key>Label</key>
        <string>com.chsharp.setmtu</string>
        <key>ProgramArguments</key>
        <array>
                <string>/Users/chsharp/bin/setmtu</string>
        </array>
        <key>RunAtLoad</key>
        <true/>
</dict>
</plist>
  1. Modify the “Label” key to be the label that you want.
  2. This launchd item will call a script when it runs. Under ProgramArguments enter the path to the script you want to run. My script is located at /Users/chsharp/bin/setmtu.
  3. When you have finished customizing the file, save it (press Control-O), press Return, and exit pico (press Control-X).
  4. Type: sudo chmod 755 MTU
  5. Press Return.

Next you have to create the script to run. The example below uses the pat that I use. You might want to use a different path where you store scripts you write.

  1. Type: cd ~/bin
  2. Press Return.
  3. Type: pico setmtu. (I use the convention com.chsharp.plist for the items that I create.)
  4. Press Return.
  5. Enter the following text
#!/bin/bash

# automatically change MTU size
# version: 0.1

# when testing for MTU size use the "ping -D -s n" command
# Set MTU to n + 28 for the value of n that works.

# Future versions:  Check Location and set MTU based on Location

# redirect all IO to /dev/null (comment this out if you want to debug)
#exec 1>/dev/null 2>/dev/null

# sleep for 60 seconds.  launchd items should live for 60 seconds.
sleep 60

#  MTU of 1400 is needed for Corporate VPNs using a Cisco 871
/sbin/ifconfig en0 mtu 1400

# MTU doesn't need to be changed for Home-Wireless
#/sbin/ifconfig en1 mtu 1460

### Always exit with 0 status
exit 0
  1. When you have finished customizing the file, save it (press Control-O), press Return, and exit pico (press Control-X).
  2. Type: sudo chmod 755 MTU
  3. Press Return.
  4. To load, enter the following
sudo launchctl load /Library/LaunchDaemons/com.xxx.setmtu.plist

Note that the script has a “sleep 60” command. launchd requires that all services it starts must run for 60 seconds.

No comments yet.

Leave a Reply