IP-L2TP(8)

๐Ÿ“ฆ
version 7.3.0 ยท 2 versions
  • 7.3.0 ยท alpine 3.22, alpine 3.23, alpine 3.24, arch rolling, centos-stream 10, centos-stream 9, debian trixie, fedora 43, fedora 44, nixos 26.05, nixpkgs unstable, opensuse-leap 16.0, ubuntu questing, ubuntu resolute, ubuntu stonking (latest)
  • 6.1.0 ยท debian bookworm, ubuntu jammy, ubuntu noble
, in alpine 3.22, alpine 3.23, alpine 3.24, arch rolling, centos-stream 10, centos-stream 9, debian trixie, fedora 43, fedora 44, nixos 26.05, nixpkgs unstable, opensuse-leap 16.0, ubuntu questing, ubuntu resolute, ubuntu stonking

๐ŸŽ€ IP-L2TP(8) ๐ŸŽ€

Linux, section 8: the manual page for ip l2tp ๐Ÿ’–

โœจ NAME โœจ

ip-l2tp - L2TPv3 static unmanaged tunnel configuration ๐Ÿฆ‹

๐Ÿ’… SYNOPSIS ๐Ÿ’…

ip [ OPTIONS ] l2tp  { COMMAND | help }

ip l2tp add tunnel
        remote ADDR local ADDR
        tunnel_id ID peer_tunnel_id ID
        [ encap { ip | udp } ]
        [ udp_sport PORT  ] [ udp_dport PORT  ]
        [ udp_csum { on | off } ]
        [ udp6_csum_tx { on | off } ]
        [ udp6_csum_rx { on | off } ]
ip l2tp add session [ name NAME  ]
        tunnel_id ID session_id ID peer_session_id ID
        [ cookie HEXSTR  ] [ peer_cookie HEXSTR  ]
        [ l2spec_type { none | default } ]
        [ seq { none | send | recv | both } ]
ip l2tp del tunnel tunnel_id ID
ip l2tp del session tunnel_id ID session_id ID
ip l2tp show tunnel [ tunnel_id ID ]
ip l2tp show session [ tunnel_id ID.B ] [ session_id ID ]
NAME := STRING
ADDR := { IP_ADDRESS | any }
PORT := { NUMBER }
ID := { NUMBER }
HEXSTR := { 8 or 16 hex digits (4 / 8 bytes) }

๐ŸŒธ DESCRIPTION ๐ŸŒธ

okay so the ip l2tp commands are how you set up static L2TPv3 ethernet tunnels, aka the so-called unmanaged kind ๐Ÿซถ For unmanaged tunnels there's no L2TP control protocol, so you don't need a userspace daemon running. You just manually create the tunnel with commands on your local system and on your remote peer. literally that's it ๐Ÿ’€

L2TPv3 is made for Layer-2 tunneling ๐Ÿงš Static tunnels are super useful for building network links across IP networks when the tunnels are fixed. An L2TPv3 tunnel can carry data for more than one session. Each session is identified by its own session_id plus the tunnel_id of its parent tunnel. And the tunnel has to exist before you can make a session inside it, so order matters bestie ๐Ÿ‘‘

When you create a tunnel you have to give the IP address of the remote peer, which can be an IPv4 or an IPv6 address. You also have to give the local IP address that will be used to reach the peer. This is the address the local system listens on, and it's where it accepts incoming L2TP data packets from the peer โœจ

L2TPv3 defines two packet encapsulation formats: UDP or IP. UDP encapsulation is the most common one, and it's giving reliable vibes ๐Ÿ’œ IP encapsulation uses a dedicated IP protocol value to carry L2TP data without the extra overhead of UDP. Only use IP encapsulation when there are no NAT devices or firewalls in the network path, because otherwise it's not going to work nicely ๐Ÿ™ˆ

When you create an L2TPv3 ethernet session, a virtual network interface is made for it. That interface has to be configured and brought up, just like any other network interface. Anything you push through that interface gets carried over the L2TP tunnel to the peer. If you set up your routing tables or add the interface to a bridge, the L2TP interface acts like a virtual wire, also known as a pseudowire, connected to the peer ๐ŸŒˆ

Setting up an unmanaged L2TPv3 ethernet pseudowire means manually creating L2TP contexts on the local system and at the peer. The parameters at each site have to match, or no data gets passed through ๐Ÿ˜ญ There are no consistency checks at all, because there's no control protocol to establish unmanaged tunnels. Once the virtual network interface of an L2TP session is configured and enabled, you can transmit data even if the peer isn't configured yet. But if the peer isn't set up, the L2TP data packets just get discarded by the peer. rip ๐Ÿ’€

To make an unmanaged L2TP tunnel, use the l2tp add tunnel and l2tp add session commands covered in this page. After that, configure and enable the tunnel's virtual network interface however you need to โœจ

Quick heads up: unmanaged tunnels only carry ethernet frames. If you need to carry PPP traffic (L2TPv2), or your peer doesn't support unmanaged L2TPv3 tunnels, you'll need an L2TP server that implements the L2TP control protocol. That protocol lets you set up dynamic L2TP tunnels and sessions, and it also detects network failures and reacts to them ๐Ÿฆ‹

๐Ÿ’– ip l2tp add tunnel - add a new tunnel ๐Ÿ’–

  • tunnel_id ID โ€” sets the tunnel id. It's a 32-bit integer that uniquely identifies the tunnel, and the value you use has to match the peer_tunnel_id value on the peer ๐Ÿซถ
  • peer_tunnel_id ID โ€” sets the peer tunnel id. It's a 32-bit integer that the peer assigned to the tunnel, and it has to match the tunnel_id value on the peer ๐ŸŽ€
  • remote ADDR โ€” sets the IP address of the remote peer. You can use an IPv4 address or an IPv6 address ๐ŸŒธ
  • local ADDR โ€” sets the IP address of the local interface that the tunnel uses. This has to be an address that actually belongs to a local interface. Again, IPv4 or IPv6 both work ๐Ÿงš
  • encap ENCAP โ€” sets the encapsulation type of the tunnel. The valid values are udp and ip ๐Ÿ’œ
  • udp_sport PORT โ€” sets the UDP source port for the tunnel. You must include it when udp encapsulation is selected. It's ignored when ip encapsulation is selected ๐ŸŒˆ
  • udp_dport PORT โ€” sets the UDP destination port for the tunnel. You must include it when udp encapsulation is selected. It's ignored when ip encapsulation is selected โญ
  • udp_csum STATE โ€” (IPv4 only) controls whether IPv4 UDP checksums get calculated and checked for the encapsulating UDP packets, when UDP encapsulation is selected. The default is off. Valid values are on and off ๐Ÿ“
  • udp6_csum_tx STATE โ€” (IPv6 only) controls whether IPv6 UDP checksums get calculated for the encapsulating UDP packets, when UDP encapsulation is selected. The default is on. Valid values are on and off ๐Ÿ”ฅ
  • udp6_csum_rx STATE โ€” (IPv6 only) controls whether IPv6 UDP checksums get checked on the encapsulating UDP packets, when UDP encapsulation is selected. The default is on. Valid values are on and off ๐Ÿ’…

โœจ EXAMPLES โœจ

๐ŸŽ€ Setup L2TP tunnels and sessions

okay so let's set up a tunnel and session between two sites bestie ๐Ÿงš

site-A:# ip l2tp add tunnel tunnel_id 3000 peer_tunnel_id 4000 \
           encap udp local 1.2.3.4 remote 5.6.7.8 \
           udp_sport 5000 udp_dport 6000
site-A:# ip l2tp add session tunnel_id 3000 session_id 1000 \
           peer_session_id 2000
site-B:# ip l2tp add tunnel tunnel_id 4000 peer_tunnel_id 3000 \
           encap udp local 5.6.7.8 remote 1.2.3.4 \
           udp_sport 6000 udp_dport 5000
site-B:# ip l2tp add session tunnel_id 4000 session_id 2000 \
           peer_session_id 1000
site-A:# ip link set l2tpeth0 up mtu 1488
site-B:# ip link set l2tpeth0 up mtu 1488

notice that the IP addresses, UDP ports and tunnel / session ids are matched and reversed at each site ๐Ÿ”„๐Ÿ’– it's giving mirror image, every single one flips! ๐Ÿชžโœจ

๐Ÿฆ‹ Configure as IP interfaces

if you only need to send IP data, you can just give both interfaces an IP address. honestly the simplest setup ever ๐Ÿฅน

site-A:# ip addr add 10.42.1.1 peer 10.42.1.2 dev l2tpeth0
site-B:# ip addr add 10.42.1.2 peer 10.42.1.1 dev l2tpeth0
site-A:# ping 10.42.1.2

now the link should be usable ๐ŸŽ‰ add static routes as needed so your data actually goes over the new link. no cap, that last step is the one people forget ๐Ÿ’…

๐ŸŒธ Configure as bridged interfaces

if you need to carry non-IP data, the L2TP interface goes into a bridge instead of getting its own IP address ๐ŸŒˆ using standard Linux utilities, obviously ๐Ÿ™„ and since raw ethernet frames are riding inside the tunnel, the MTU of the L2TP interfaces has to be set so there's room for those headers ๐Ÿ“ฆ

site-A:# ip link set l2tpeth0 up mtu 1446
site-A:# ip link add br0 type bridge
site-A:# ip link set l2tpeth0 master br0
site-A:# ip link set eth0 master br0
site-A:# ip link set br0 up

if you're using VLANs, set up a bridge per VLAN and bridge each VLAN over its own L2TP session ๐ŸŽ€ for example, to bridge VLAN ID 5 on eth1 over an L2TP pseudowire:

site-A:# ip link set l2tpeth0 up mtu 1446
site-A:# ip link add brvlan5 type bridge
site-A:# ip link set l2tpeth0.5 master brvlan5
site-A:# ip link set eth1.5 master brvlan5
site-A:# ip link set brvlan5 up

adding the L2TP interface to a bridge makes the bridge forward traffic over the pseudowire just like it does over any other interface ๐Ÿฆ‹ the bridge learns the MAC addresses of hosts on each interface and smartly forwards frames from one bridge port to another. the l2tpethN interfaces do not get IP addresses in this setup ๐Ÿ™…โ€โ™€๏ธ and if the bridge is set up correctly on both sides of the pseudowire, you should be able to reach hosts on the peer's bridged network. slay ๐Ÿ‘‘

heads up, this one's a little drama ๐Ÿ˜ญ when raw ethernet frames get bridged across an L2TP tunnel, big frames may get fragmented and forwarded to the recipient as individual IP fragments. this depends on the MTU of the physical interface the tunnel uses ๐Ÿ’€ when the frames carry protocols the recipient reassembles, like IP, it's fine. but fragmentation can break protocols like PPPoE, where the recipient expects ethernet frames exactly as they were sent ๐Ÿ™ˆ so in those cases, frames leaving the tunnel need to be reassembled into a single frame before they get forwarded. to make that happen, enable netfilter connection tracking (conntrack) or manually load the Linux netfilter defrag modules at each tunnel endpoint ๐Ÿงผ

site-A:# modprobe nf_defrag_ipv4
site-B:# modprobe nf_defrag_ipv4

if you're running L2TP over IPv6, use the IPv6 defrag module instead ๐ŸŒ


โœจ INTEROPERABILITY โœจ

okay so interop is kinda a whole thing ๐Ÿซถ unmanaged (static) L2TPv3 tunnels are supported by some network equipment vendors, like Cisco ๐Ÿ”ฅ

in Linux, L2TP Hello messages are not supported in unmanaged tunnels ๐Ÿ™…โ€โ™€๏ธ quick context: Hello messages are how L2TP clients and servers detect link failures, so they can automatically tear down and re-establish dynamic tunnels ๐Ÿ” if a non-Linux peer supports Hello messages in unmanaged tunnels, you have to turn them off to interoperate with Linux ๐Ÿ’…

Linux defaults to the Default Layer2SpecificHeader type from the L2TPv3 protocol spec, RFC3931 ๐Ÿ“œ this setting has to match what's configured on the peer, or it's a no-go ๐Ÿ’€ some vendor implementations (e.g. Cisco) default to a Layer2SpecificHeader type of None, so double check! ๐Ÿ™ˆ

โœจ SEE ALSO โœจ

ip(8) ๐Ÿงš


โœจ AUTHOR โœจ

James Chapman <jchapman@katalix.com> ๐Ÿ‘‘๐Ÿ’–


and that's a wrap bestie ๐ŸŽ€ this page came from iproute2, dated 19 Apr 2012, and it's the one and only IP-L2TP(8) ๐Ÿ’…โœจ go set up that tunnel and text me when the ping works ๐Ÿฅฐ๐Ÿฆ‹