Discussion:
[Openvpn-users] Fragmentation question regarding OpenVPN
Jason Haar
2005-02-14 20:52:12 UTC
Permalink
A couple of years ago, I was a bit of a keen user of FreeSWAN (now
OpenSWAN), and one feature they had - which I haven't see any mention of
in OpenVPN - was that the ipsec interfaces had an MTU of 16260 instead
of the more standard 1500.

The rationale was that there are LOTS of broken firewalls and gateways
out there on the Internet that cannot handle fragmentation correctly
(typically they are dropping the ICMP "frag-required" packets and don't
realize fragmentation is needed). So by making the IPSec interfaces
think they have a large MTU, when a *client* sends a "full", 1500 byte
packet to the VPN router, the router *doesn't* send back a "frag
required" packet - as the interface it's forwarding to has an MTU of
16260. Then it's purely OpenSWANs problem to deal with frags thereafter
- and it's something the owner can control via the "overridemtu" statement.

Anyway, I see tun* interfaces have an MTU of 1500... Is there a way of
emulating this OpenSWAN behavior? i.e. to make fragmentation OpenVPNs
problem instead of end-user?
--
Cheers

Jason Haar
Information Security Manager, Trimble Navigation Ltd.
Phone: +64 3 9635 377 Fax: +64 3 9635 417
PGP Fingerprint: 7A2E 0407 C9A6 CAF6 2B9F 8422 C063 5EBB FE1D 66D1
James Yonan
2005-02-15 06:02:08 UTC
Permalink
Post by Jason Haar
A couple of years ago, I was a bit of a keen user of FreeSWAN (now
OpenSWAN), and one feature they had - which I haven't see any mention of
in OpenVPN - was that the ipsec interfaces had an MTU of 16260 instead
of the more standard 1500.
The rationale was that there are LOTS of broken firewalls and gateways
out there on the Internet that cannot handle fragmentation correctly
(typically they are dropping the ICMP "frag-required" packets and don't
realize fragmentation is needed). So by making the IPSec interfaces
think they have a large MTU, when a *client* sends a "full", 1500 byte
packet to the VPN router, the router *doesn't* send back a "frag
required" packet - as the interface it's forwarding to has an MTU of
16260. Then it's purely OpenSWANs problem to deal with frags thereafter
- and it's something the owner can control via the "overridemtu" statement.
Anyway, I see tun* interfaces have an MTU of 1500... Is there a way of
emulating this OpenSWAN behavior? i.e. to make fragmentation OpenVPNs
problem instead of end-user?
OpenVPN doesn't use large MTU sizes like 16260. It just uses 1500 because
that is the size least likely to break applications which are talking over
the VPN.

If 1500 is too large for your network path, you can use the mssfix
directive to very efficiently scale down tunneled TCP connections to a
smaller MSS value, so that they don't hit the full 1500 limit and trigger
fragmentation. The cool thing about mssfix is that it configures TCP
senders to use smaller segments to begin with, so that fragmentation is
unnecessary -- the net effect is that it solves the fragmentation problem
with almost no performance penalty.

You can also tell OpenVPN to handle fragmentation internally by using the
"fragment" directive on both sides of the connection. "fragment" is more
like the FreeSWAN/OpenSWAN feature you describe in that it tells OpenVPN
to do fragmentation internally. But it's only really needed for non-TCP
protocols running over the VPN (like UDP), because mssfix efficiently
takes care of the TCP case.

James
Jamie Lokier
2005-02-15 11:31:25 UTC
Permalink
Post by James Yonan
If 1500 is too large for your network path, you can use the mssfix
directive to very efficiently scale down tunneled TCP connections to a
smaller MSS value, so that they don't hit the full 1500 limit and trigger
fragmentation. The cool thing about mssfix is that it configures TCP
senders to use smaller segments to begin with, so that fragmentation is
unnecessary -- the net effect is that it solves the fragmentation problem
with almost no performance penalty.
You can also tell OpenVPN to handle fragmentation internally by using the
"fragment" directive on both sides of the connection. "fragment" is more
like the FreeSWAN/OpenSWAN feature you describe in that it tells OpenVPN
to do fragmentation internally. But it's only really needed for non-TCP
protocols running over the VPN (like UDP), because mssfix efficiently
takes care of the TCP case.
Is there a way to have OpenPVN respond to DF (Don't Fragment) messages
caused by the UDP tunnel packets, and automatically reduce the
endpoint MTU in response to that?

At home, I have to explicitly uses a small MTU on my tunnels otherwise
I get stuck TCP connections some of the time - but only when
tunnelling over dialup. At other times, a larger MTU works and is
better. It would be nice if OpenVPN would automatically adjust the
interface MTU according to ordinary path MTU discovery procedures.

Alternatively, it be nice if OpenVPN would convert DF messages in
response to UDP tunnel packets into DF messages from the tunnel
interface, so that application or TCP path MTU discovery works.

-- Jamie
James Yonan
2005-02-15 15:32:18 UTC
Permalink
Post by Jamie Lokier
Post by James Yonan
If 1500 is too large for your network path, you can use the mssfix
directive to very efficiently scale down tunneled TCP connections to a
smaller MSS value, so that they don't hit the full 1500 limit and trigger
fragmentation. The cool thing about mssfix is that it configures TCP
senders to use smaller segments to begin with, so that fragmentation is
unnecessary -- the net effect is that it solves the fragmentation problem
with almost no performance penalty.
You can also tell OpenVPN to handle fragmentation internally by using the
"fragment" directive on both sides of the connection. "fragment" is more
like the FreeSWAN/OpenSWAN feature you describe in that it tells OpenVPN
to do fragmentation internally. But it's only really needed for non-TCP
protocols running over the VPN (like UDP), because mssfix efficiently
takes care of the TCP case.
Is there a way to have OpenPVN respond to DF (Don't Fragment) messages
caused by the UDP tunnel packets, and automatically reduce the
endpoint MTU in response to that?
At home, I have to explicitly uses a small MTU on my tunnels otherwise
I get stuck TCP connections some of the time - but only when
tunnelling over dialup. At other times, a larger MTU works and is
better. It would be nice if OpenVPN would automatically adjust the
interface MTU according to ordinary path MTU discovery procedures.
There are problems with this:

* Path MTU discovery is often broken in the real world, because of
firewall blockage of certain kinds of ICMP and fragment handling policies.

* Some OSes like Windows cannot change network adapter MTUs on the fly --
the device driver would need to be unloaded and reloaded.

* Even when PMTU discovery succeeds, there's no mechanism in the standard
Berkeley sockets API to message the discovered value back to the socket
client. Linux has some non-portable code to do this already which has
been implemented in OpenVPN's mtu.c.
Post by Jamie Lokier
Alternatively, it be nice if OpenVPN would convert DF messages in
response to UDP tunnel packets into DF messages from the tunnel
interface, so that application or TCP path MTU discovery works.
This should already work. Suppose tun0 has been configured with an MTU of
1200. If an application tries to send a 1400 byte UDP packet through
tun0, a "fragmentation needed but DF set" ICMP message should be echoed by
the kernel, independently of OpenVPN.

The bigger problem is that OpenVPN doesn't know the maximum UDP packet
size which can be sent between two points, without the expensive
--mtu-test procedure. If it knew this value, it could then set --mssfix
and --fragment dynamically (but still leave the TUN/TAP interface MTU at
1500).

James
Jamie Lokier
2005-02-15 15:42:04 UTC
Permalink
Post by James Yonan
Post by Jamie Lokier
Alternatively, it be nice if OpenVPN would convert DF messages in
response to UDP tunnel packets into DF messages from the tunnel
interface, so that application or TCP path MTU discovery works.
This should already work. Suppose tun0 has been configured with an MTU of
1200. If an application tries to send a 1400 byte UDP packet through
tun0, a "fragmentation needed but DF set" ICMP message should be echoed by
the kernel, independently of OpenVPN.
The bigger problem is that OpenVPN doesn't know the maximum UDP packet
size which can be sent between two points, without the expensive
--mtu-test procedure. If it knew this value, it could then set --mssfix
and --fragment dynamically (but still leave the TUN/TAP interface MTU at
1500).
My problem is that the maximum UDP packet size that OpenVPN can use
varies, depending on which physical link it's using.

For me the whole point of using OpenVPN is to maintain a stable
virtual link over many different underlying links - it's used from a
laptop, which connects physically in whatever way it can when I travel.

Sometimes, the maximum UDP packet size is quite small. I solve this
by using an explicit "ifconfig tun0 mtu 308" in my OpenVPN startup
script. Otherwise, TCP connections going over the link can stall.

But at other times, that MTU of 308 is unnecessarily restrictive, and
reduces the bandwidth I can attain by a measurable amount.

This is with Linux at both ends, so the MTU discovery code you mention
should be automatic without me having to explicitly ifconfig,
shouldn't it?

-- Jamie
Jason Haar
2005-02-15 16:10:06 UTC
Permalink
Post by Jamie Lokier
This is with Linux at both ends, so the MTU discovery code you mention
should be automatic without me having to explicitly ifconfig,
shouldn't it?
-- Jamie
Have you checked your firewall settings? I recently got stung by that
(too anal on my iptables ;-) Next time it happens, you could try just
disabling your firewall for a minute (you're fully patched - right? :-)
and see if the problem goes away.

I've had that problem even with HTTPS web pages over wireless on Linux
(i.e no VPN). I had a situation on my laptop where HTTPS (with large
server and client certs that lead to "full" packets) works fine over
Ethernet, but if I change over to wireless, suddenly they hang. tcpdump
shows ICMP "frag packet" error packets coming in and being ignored. Then
I disable my firewall and the problem goes away. Weirds me out as I was
under the impression 802.11* had the same MTU as Ethernet.

Fragmentation is a much larger problem than it used to be. "In the old
days" very little needed fragmenting, but now with things like
certificates and especially Active Directory Kerberos traffic, it's
happening a lot.

Now you see why I brought it up :-)

PS: Cisco whitepapers say you should force the MTU of your end-user
facing interfaces down to 1412 (or similar) specifically for this
reason. Make the end-Ethernet devices start fragmenting early, so the
VPN tunnel doesn't have to. It's also a load issue. It's a lot cheaper
for end machines to fragment than for a VPN router with 1,000s of
current connections having to do that work for them (and no comments
about Ciscos CPUs please! ;-)
--
Cheers

Jason Haar
Information Security Manager, Trimble Navigation Ltd.
Phone: +64 3 9635 377 Fax: +64 3 9635 417
PGP Fingerprint: 7A2E 0407 C9A6 CAF6 2B9F 8422 C063 5EBB FE1D 66D1
James Yonan
2005-02-15 16:21:56 UTC
Permalink
Post by Jamie Lokier
Post by James Yonan
Post by Jamie Lokier
Alternatively, it be nice if OpenVPN would convert DF messages in
response to UDP tunnel packets into DF messages from the tunnel
interface, so that application or TCP path MTU discovery works.
This should already work. Suppose tun0 has been configured with an MTU of
1200. If an application tries to send a 1400 byte UDP packet through
tun0, a "fragmentation needed but DF set" ICMP message should be echoed by
the kernel, independently of OpenVPN.
The bigger problem is that OpenVPN doesn't know the maximum UDP packet
size which can be sent between two points, without the expensive
--mtu-test procedure. If it knew this value, it could then set --mssfix
and --fragment dynamically (but still leave the TUN/TAP interface MTU at
1500).
My problem is that the maximum UDP packet size that OpenVPN can use
varies, depending on which physical link it's using.
For me the whole point of using OpenVPN is to maintain a stable
virtual link over many different underlying links - it's used from a
laptop, which connects physically in whatever way it can when I travel.
Sometimes, the maximum UDP packet size is quite small. I solve this
by using an explicit "ifconfig tun0 mtu 308" in my OpenVPN startup
script. Otherwise, TCP connections going over the link can stall.
But at other times, that MTU of 308 is unnecessarily restrictive, and
reduces the bandwidth I can attain by a measurable amount.
An MTU of 308 is below the minimum guidelines for running TCP over the
link.
Post by Jamie Lokier
This is with Linux at both ends, so the MTU discovery code you mention
should be automatic without me having to explicitly ifconfig,
shouldn't it?
Do you get an EMSGSIZE error from OpenVPN if you overflow the MTU? If so,
that means the Linux kernel is receiving the "Fragmentation needed but DF
set" messages. There's code as well in mtu.c which will output the PMTU
size to the log file if the kernel sends us a message about it (all this
PMTU code in mtu.c is Linux-specific). Different --mtu-disc settings will
affect this instrumentation.

If you can't get the PMTU size from the kernel, then you have to use an
empirical method like --mtu-test which sends variable length UDP packets
and sees which ones actually get through. Theoretically, one could speed
up mtu-test, have it run on OpenVPN initialization/restart, and use the
resulting value to automatically set mssfix and fragment. Because these
variables are internal to OpenVPN they can be changed on the fly, unlike
the interface MTU which is not portably dynamic.

James

Loading...