IP-L2TP(8)
๐ 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 thepeer_tunnel_idvalue 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 thetunnel_idvalue 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 areudpandip๐udp_sport PORTโ sets the UDP source port for the tunnel. You must include it whenudpencapsulation is selected. It's ignored whenipencapsulation is selected ๐udp_dport PORTโ sets the UDP destination port for the tunnel. You must include it whenudpencapsulation is selected. It's ignored whenipencapsulation 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 isoff. Valid values areonandoff๐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 ison. Valid values areonandoff๐ฅ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 ison. Valid values areonandoff๐
โจ 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 ๐ฅฐ๐ฆ
๐ฆ where this page comes from
- alpine 3.22: iproute2-doc 6.15.0-r0 ยท GPL-2.0-or-later
- alpine 3.23: iproute2-doc 6.17.0-r0 ยท GPL-2.0-or-later
- alpine 3.24: iproute2-doc 7.0.0-r0 ยท GPL-2.0-or-later
- arch rolling: iproute2 7.2.0-1
- arch rolling: iproute2 7.3.0-1 ยท GPL-2.0-or-later
- centos-stream 10: iproute 7.0.0-2.el10 ยท GPL-2.0-or-later AND NIST-PD
- centos-stream 9: iproute 6.17.0-3.el9 ยท GPL-2.0-or-later AND NIST-PD
- debian trixie: iproute2 6.15.0-1 ยท GPL-2.0-only
- fedora 43: iproute 6.14.0-2.fc43 ยท GPL-2.0-or-later AND NIST-PD
- fedora 44: iproute 6.17.0-2.fc44 ยท GPL-2.0-or-later AND NIST-PD
- nixos 26.05: iproute2 7.0.0
- nixpkgs unstable: iproute2 7.2.0
- opensuse-leap 16.0: iproute2 6.12-160000.4.1 ยท GPL-2.0-only
- opensuse-leap 16.0: iproute2 6.12-160000.4.1 ยท GPL-2.0-only
- opensuse-leap 16.0: iproute2 6.12-160000.4.1 ยท GPL-2.0-only
- opensuse-leap 16.0: iproute2 6.12-160000.4.1 ยท GPL-2.0-only
- ubuntu questing: iproute2 6.16.0-1ubuntu2
- ubuntu questing: iproute2 6.16.0-1ubuntu2.1 ยท GPL-2.0-only
- ubuntu questing: iproute2 6.16.0-1ubuntu2.2
- ubuntu resolute: iproute2 6.19.0-1ubuntu1 ยท GPL-2.0-only
- ubuntu resolute: iproute2 6.19.0-1ubuntu1.1 ยท GPL-2.0-only
- ubuntu stonking: iproute2 7.2.0-1ubuntu1 ยท GPL-2.0-only
- ๐ girlified by anthropic/claude-haiku-5.5 on : a language model's rewrite of the original, under its terms