14:45 - Thursday, 17 April 2014

How To Tell What MTU Is Being Used In Windows XP

I’m suffering from a really weird problem where I randomly get “The connection to the server was reset” errors when trying to access web pages (HTTP error 12031 according to the Windows network diagnostic tool) – this happens regardless of whether the web page I’m trying to access is on the external internet or even if it’s from a local Apache instance running on localhost. It affects all of the computers on our local network (Ethernet, not wireless), all of which are running Windows XP.

It has been suggested to me that it might be to do with the MTU used on network traffic. If I do the Ping Test to find out the largest packet that can go through unfragmented, I can ping the localhost with a package of 1492 bytes (+28 bytes for a header?) and I can ping our router with a package of 1462 bytes (which is 1490 bytes when you include the 28 byte header). If I try and ping something on the outside like Google, I can’t get anything through bigger than 1430 (which is 1458 with the header).

I’ve tried following various sets of instructions to update the Windows XP Registry with this MTU setting, updating HKLMSYSTEMCurrentControlSetServicesTcpipParametersInterfaces{AdapterID}MTU. I’ve tried no end of alternative values: the most obvious correct value seems to be 1490, but I’ve also tried 1462, 1458, 1430, etc., etc. When I reboot the computer to make the change take effect, it seems to work for a few minutes (hard to tell for certain since it’s always random rather than consistent) but it never lasts long.

Initially, when I was trying 1430 as a value, after a few minutes of working fine, the results of the Ping Test would decrease by 28 bytes – suddenly I’d find that I could only get a package of 1402 bytes through to Google. If I updated the MTU registry setting to 1402, when I rebooted and waited a few minutes, it’d then be 1374, then 1346, etc. etc. Other computers on the network remained unaffected (still at 1430) and removing the MTU setting from the registry would restore things to normal (and still broken).

The thing that I find the hardest about diagnosing all this is that it’s very hard to tell if I’m even playing with the correct registry setting. So at it’s simplest, my question would be: How can I tell what MTU setting Windows is trying to use?

Also, if anybody has any ideas how to tell why the MTU keeps dropping by 28, that would be useful too (e.g. is there a Windows log file somewhere where it will log something at the point where the value changes?)

Finally, if anybody can tell me definitively how to tell what MTU setting I should be trying to use, that would be great!

For Windows 7, Windows Vista and Windows XP, the MTU for various interfaces is available from Windows itself using netsh.

Windows 7, Windows Vista

To show current MTU on Windows 7 or Windows Vista, from a command prompt:

C:UsersIan>netsh interface ipv6 show subinterfaces       MTU  MediaSenseState   Bytes In  Bytes Out  Interface----------  ---------------  ---------  ---------  -------------      1280                1   24321220    6455865  Local Area Connection4294967295                1          0    1060111  Loopback Pseudo-Interface 1      1280                5          0          0  isatap.newland.com      1280                5          0          0  6TO4 Adapter

And for IPv4 interfaces:

C:UsersIan>netsh interface ipv4 show subinterfaces       MTU  MediaSenseState   Bytes In  Bytes Out  Interface----------  ---------------  ---------  ---------  -------------      1500                1  146289608   29200474  Local Area Connection4294967295                1          0      54933  Loopback Pseudo-Interface 1

Note: In this example my Local Area Connection IPv6 interface has such a low MTU (1280) because i’m using a tunnel service to get IPv6 connectivity.

You can also change your MTU (Windows 7, Windows Vista). From an elevated command prompt:

>netsh interface ipv4 set subinterface "Local Area Connection" mtu=1492 store=persistentOk.

Tested with Windows 7 Service Pack 1

Windows XP

The netsh syntax for Windows XP is slightly different:

C:UsersIan>netsh interface ip show interfaceIndex:                                  1User-friendly Name:                     LoopbackType:                                   LoopbackMTU:                                    32767Physical Address:                       Index:                                  2User-friendly Name:                     Local Area ConnectionType:                                   EtherenetMTU:                                    1500Physical Address:                       00-03-FF-D9-28-B7

Note: Windows XP requires that the Routing and Remote Access service be started before you can see details about an interface (including MTU):

C:UsersIan>net start remoteaccesss

Windows XP does not provide a way to change the MTU setting from within netsh. For that you can:

Tested with Windows XP Service Pack 3

See also

Short discussion on what MTU is, where the 28 bytes is coming from.

Your network card (Ethernet) has a maximum packet size of 1,500 bytes:

+---------+| 1500    || byte    || payload ||         ||         ||         |+---------+

The IP portion of TCP/IP requires a 20 byte header (12 bytes of flags, 4 bytes for source IP address, 4 bytes for destination IP address). This leaves less space available in the packet:

+------------------------+| 12 bytes control flags | | 4 byte from address    | |- IP header: 20 bytes| 4 byte to address      | /|------------------------|| 1480 byte payload      ||                        ||                        ||                        |+------------------------+

Now an ICMP (ping) packet has an 8-byte header (1 byte type, 1 byte code, 2 byte checksum, 4 byte additional data):

+------------------------+| 12 bytes control flags | | 4 byte from address    | || 4 byte to address      | |- IP and ICMP header: 28 bytes|------------------------| || 8 byte ICMP header     | /|------------------------|| 1472 byte payload      ||                        ||                        ||                        |+------------------------+

That’s where the “missing” 28 bytes is – it’s the size of the headers required to send a ping packet.

When you send a ping packet, you can specify how much extra payload data you’d like to include. In this case, if you include all 1472 bytes:

>ping -l 1472 obsidian

Then the resulting ethernet packet will be full to the gills. Every last byte of the 1500 byte packet will be filled:

+------------------------+| 12 bytes control flags | | 4 byte from address    | || 4 byte to address      | |- IP and ICMP header: 28 bytes|------------------------| || 8 byte ICMP header     | /|------------------------||........................||........................||. 1472 bytes of junk....||........................||........................||........................||........................|+------------------------+

If you try to send one more byte

>ping -l 1473 obsidian

the network will have to fragment that 1501 byte packet into multiple packets:

Packet 1 of 2+------------------------+| 20 bytes control flags | | 4 byte from address    | || 4 byte to address      | |- IP and ICMP header: 28 bytes|------------------------| || 8 byte ICMP header     | /|------------------------||........................||........................||..1472 bytes of payload.||........................||........................||........................||........................|+------------------------+Packet 2 of 2+------------------------+| 20 bytes control flags | | 4 byte from address    | || 4 byte to address      | |- IP and ICMP header: 28 bytes|------------------------| || 8 byte ICMP header     | /|------------------------||.                       || 1 byte of payload      ||                        ||                        ||                        ||                        ||                        |+------------------------+

This fragmentation will happen behind the scenes, ideally without you knowing.

But you can be mean, and tell the network that the packet is not allowed to be fragmented:

>ping -l 1473 -f obsidian

The -f flag means do not fragment. Now when you try to send a packet that doesn’t fit on the network you get the error:

>ping -l 1473 -f obsidian  Packet needs to be fragmented but DF set.

The packet needs to be fragmented, but the Do not Fragment flag was set.

If anywhere along the line a packet needed to be fragmented, the network actually sends an ICMP packet telling you that a fragmentation happened. Your machine gets this ICMP packet, is told what the largest size was, and is supposed to stop sending packets too big. Unfortunately most firewalls block these “Path MTU discovery” ICMP packets, so your machine never realizes the packets are being fragmented (or worse: dropped because they couldn’t be fragmented).

That’s what causes web-server to not work. You can get the initial small (<1280 byte) responses, but larger packets can't get through. And the web-server's firewalls are misconfigured, blocking ICMP packets. So the web-server doesn't realize you never got the packet.

Fragmentation of packets is not allowed in IPv6, everyone is required to (correctly) allow ICMP mtu discovery packets.

@ian I’m not so sure that netsh actually shows the currently used MTU. On my Windows XP Pro SP3 machine, I executed netsh interface ip show interface and it reported the MTU value for the relevant interface as 1500. I then added the following registry keys:

HKEY_LOCAL_MACHINESYSTEMCurrentControlSetServicesTcpipParametersEnablePMTUDiscovery    value: 0HKEY_LOCAL_MACHINESYSTEMCurrentControlSetServicesTcpipParametersInterfaces{ID}MTU     value: various (e.g. 1200)

Microsoft says that setting EnablePMTUDiscovery to 0 will set MTU to 576.

Setting the MTU registry entry sets the MTU manually. I tried several values for the MTU entry (rebooting each time).

In both cases — adding the first entry, then the second entry — netsh still reported the MTU as 1500. Testing with ping confirmed (or at least suggested) that the MTU value configured in the registry was actually being used though.

Also, when I first tried this on my machine, the Routing and Remote Access service was disabled, so I was unable to start it using your instructions. I enabled it by going to Control Panel > Adminstrative Tools > Computer Management > Services and Applications > Services. I changed “Startup type” from Disabled to Manual. I then started the service from that dialog as well.

I’m also not sure that KB283165 is necessarily the correct instructions for changing the MTU. Aren’t those instructions only relevant when running the Windows PPPoE client? If connecting to the internet through a router where the router is the PPPoE client (as in my case), those instructions wouldn’t be relevant, right?

The instructions I followed, which led me to make the above changes to the registry, were in KB900926: Recommended TCP/IP settings for WAN links with a MTU size of less than 576 (methods 2 & 3).

Edit by @ian

Looks like you’re right. Configure for 1,200, but netsh reports 1500.

enter image description here

>ping -l 1173 -f obsidianPacket needs to be fragmented but DF set.

So i guess the answer to the original question is that on Windows XP you have to use trial-and-error with the Do not fragment flag to find the biggest packet you can send is. Then you have your MTU.

See AdapterWatch:

AdapterWatch displays useful
information about your network
adapters: IP addresses, Hardware
address, WINS servers, DNS servers,
MTU value, Number of bytes received or
sent, The current transfer speed, and
more. In addition, it displays general
TCP/IP/UDP/ICMP statistics for your
local computer.

Microsoft KB314496: The default MTU sizes for different network topologies.
You should not try to play with the MTU configuration in normal network setups.

There is a VB code reference here.
There is also a tool called DrTCP:

alt text

In the registry,

  • Go to HKLMSoftwareMicrosoftWindows NTCurrentVersionNetworkCards
  • Open the adapter that you are interested in
  • Copy the ServiceName string
  • Search that string in HKLMSystem; you will match a NetCfgInstanceId key
  • A little above that will be the MaxFrameSize key (mine shows 1514)

There is also a way to change this with the netsh command.

Also, check your Path MTU Discovery configuration.

You can find MTU using ping with trial and error approach:

-f -l nnnn


-f : Specifies that Echo Request messages are sent with the Don’t Fragment flag in the IP header set to 1. The Echo Request message cannot be fragmented by routers in the path to the destination. This parameter is useful for troubleshooting path Maximum Transmission Unit (PMTU) problems.

-l Size : Specifies the length, in bytes, of the Data field in the Echo Request messages sent. The default is 32. The maximum size is 65,527.

You will get “Packet needs to be fragmented but DF set” messages when the length is too big.