IPIP tunneling in Linux (Ubuntu)

I think the increasingly low use of IPIP, i.e. IP-in-IP or IP-IP, tunneling these past few decades has resulted in very little documentation on how to set it up on a modern OS and/or not involving an ancient Cisco router.

I was trying to solve a very weird issue where two remote networks are connected via a fast (10gig) but somewhat lossy (0.1%-1%) point to point link. The lossiness of the link makes typical TCP congestion control algorithms, even in modern linux kernels, think the connection is congested rather than just lossy. This results in retransmits and frequent shrinking of the TCP window, producing horrid throughput.

Well, first solution I found to that was to use the BBR congestion control algorithm instead. BBR is a bad idea if your network is truly congested, but it is very good in situations with low amounts of loss either due to the network, or the target endpoints, because it is very aggressive in using a large TCP window even after loss and retransmits occur. That’s why you’d not use it on a truly congested network, because it will just compound the problem by continuing to dump high volumes of traffic in.

Anyway, my problem is I have two particularly ancient devices in different data centers that had been connected across this lossy link, and they have a horribly out of date networking stack that reacts horribly to loss. I thought to myself, how about I tunnel between the two devices across the lossy link, so they do not see the loss occurring behind the scenes that the tunnel servers deal with. I wanted the simplest tunnel possible, and came back to good ol’ IPIP. I also have jumbo frame support on this point to point, so I don’t even have to worry about fragmentation.

So here we go:

  • Modern Ubuntu 22LTS system on each end
  • Internal network at location A, connected on network interface ens224
  • Internal network at location B, connected on network interface ens224
  • Tunnel server at location A has internet-connected interface ens192 configured as
  • Tunnel server at location B has internet-connected interface ens192 configured as

I just used a few commands to bring the IPIP tunnel up (and get rid of it in case it was already up and producing an error about ‘add tunnel “tunl0” failed: File exists’.

System at location A:

rmmod ipip
# ubuntu will auto load ipip mod with next command
ip tunnel add locA2locB mode ipip remote local
echo 1 > /proc/sys/net/ipv6/conf/ens224/forwarding
ip link set locA2locB up
ip route add dev locA2locB
Code language: PHP (php)

System at location B:

rmmod ipip
# ubuntu will auto load ipip mod with next command
ip tunnel add locB2locA mode ipip remote local
echo 1 > /proc/sys/net/ipv6/conf/ens224/forwarding
ip link set locB2locA up
ip route add dev locB2locA
Code language: PHP (php)

That’s it. As long as you don’t have a firewall getting in the way of this, the tunnel interfaces should now be up and the internal-facing ens224 interfaces should accept and route packets for internal systems across the tunnel. The tunnel will not encapsulate ethernet, as this is not a bridge, nor will it handle multicast; strictly IP in IP.

This solved my problem; now the tunnel servers and IPIP deliver the packets between the two problem systems regardless of loss occurring on the tunnel side, and those systems keep their TCP window as open as their old stack allows, so throughput remains high.

Leave a Reply

Your email address will not be published. Required fields are marked *