How to Create and Configure L2TPv3 Ethernet Pseudowire Tunnels in Linux Using ip l2tp

Modern enterprise networking and cloud virtualization frequently require bridging Layer 2 Ethernet broadcast domains across routed Layer 3 IP networks. While protocols like GRE, VXLAN, and OpenVPN are widely used, L2TPv3 (Layer 2 Tunneling Protocol Version 3), defined in RFC 3931, offers an ultra-lightweight, high-performance alternative for point-to-point Ethernet pseudowires. Because the Linux kernel natively manages L2TPv3 encapsulation and decapsulation in kernel space via dedicated networking submodules, it avoids costly context switches between kernel and userspace, delivering near-wire-speed throughput with minimal CPU overhead.

The native iproute2 suite provides complete support for L2TPv3 through the ip l2tp management tool. Whether you are interconnecting remote testing laboratories, trunking tagged VLAN frames across disparate cloud VPCs, or establishing transparent Ethernet links between servers, configuring static L2TPv3 tunnels directly from the terminal is fast, reliable, and scriptable. In this tutorial, we explore how to load required kernel modules, establish L2TPv3 tunnels and sessions, configure network addresses or bridges, and monitor operational telemetry.

Understanding L2TPv3 Tunnel Architecture

Unlike dynamic tunneling solutions that rely on continuous daemon negotiations (such as xl2tpd), the Linux kernel supports static, unmanaged L2TPv3 pseudowires. The architecture comprises two hierarchical entities:

  • The Tunnel: Defines the Layer 3 transport conduit between two IP endpoints. A tunnel binds a local IP, remote peer IP, encapsulation method (UDP or raw IP protocol 115), and a numeric tunnel identifier.
  • The Session: Represents an individual data channel carried within the tunnel. For Ethernet pseudowires, creating a session instantiates a virtual network interface (typically named l2tpeth0, l2tpeth1, etc.) that accepts and transmits raw 802.3 Ethernet frames. Multiple independent sessions can traverse a single underlying tunnel.

Step 1: Loading Required Linux Kernel Modules

L2TPv3 functionality depends on specific kernel networking drivers that are typically compiled as loadable kernel modules in standard Linux distributions like Ubuntu, Debian, Red Hat Enterprise Linux, and Arch Linux.

Open your terminal and load the core L2TP and Ethernet pseudowire modules using modprobe:

sudo modprobe l2tp_core
sudo modprobe l2tp_netlink
sudo modprobe l2tp_eth

Verify that the modules are loaded into the running kernel:

lsmod | grep l2tp

To ensure these modules initialise automatically on system boot, add them to your static module configuration file:

echo -e "l2tp_core\nl2tp_netlink\nl2tp_eth" | sudo tee -a /etc/modules-load.d/l2tp.conf

Step 2: Creating the L2TPv3 Tunnel Endpoint

In this scenario, consider two Linux hosts: Host A (local IP: 198.51.100.10) and Host B (remote peer IP: 203.0.113.20). We will create a tunnel using UDP encapsulation over port 5000.

Execute the following command on Host A to establish the tunnel:

sudo ip l2tp add tunnel \
    tunnel_id 1000 \
    peer_tunnel_id 2000 \
    encap udp \
    local 198.51.100.10 \
    remote 203.0.113.20 \
    udp_sport 5000 \
    udp_dport 5000

Key parameters explained:

  • tunnel_id 1000: The local numeric identifier for this tunnel (must be unique on this host).
  • peer_tunnel_id 2000: The remote tunnel ID that Host B will configure as its local identifier.
  • encap udp: Encapsulates L2TP frames inside standard UDP datagrams, ensuring smooth traversal through NAT routers and stateful firewalls. (Alternatively, encap ip uses raw IP protocol 115 if firewalls permit).
  • udp_sport 5000 and udp_dport 5000: Source and destination UDP ports used for transit.

Next, log into Host B and run the reciprocal command, reversing the local and peer parameters:

sudo ip l2tp add tunnel \
    tunnel_id 2000 \
    peer_tunnel_id 1000 \
    encap udp \
    local 203.0.113.20 \
    remote 198.51.100.10 \
    udp_sport 5000 \
    udp_dport 5000

Step 3: Creating the L2TPv3 Ethernet Session

Once the transport tunnel is defined, you must instantiate a session inside it to generate the virtual Ethernet pseudowire interface.

On Host A, create session ID 1:

sudo ip l2tp add session \
    tunnel_id 1000 \
    session_id 1 \
    peer_session_id 1

On Host B, create the matching session endpoint:

sudo ip l2tp add session \
    tunnel_id 2000 \
    session_id 1 \
    peer_session_id 1

As soon as this command executes, the Linux kernel creates a new network device named l2tpeth0. Check its presence using ip link:

ip link show l2tpeth0

Step 4: Configuring and Bringing Up the Pseudowire Interface

The newly generated l2tpeth0 device behaves exactly like a physical Ethernet adapter. You can either assign IP addresses directly to each end or attach the interface to a network bridge.

Method 1: Direct Point-to-Point Addressing

To establish a private routed subnet across the tunnel, assign an IP and bring the link state up on Host A:

sudo ip addr add 10.100.0.1/24 dev l2tpeth0
sudo ip link set l2tpeth0 up

On Host B, configure the peer address and bring the interface online:

sudo ip addr add 10.100.0.2/24 dev l2tpeth0
sudo ip link set l2tpeth0 up

Verify end-to-end pseudowire connectivity by sending ICMP echo requests across the tunnel:

ping -c 4 10.100.0.2

Method 2: Bridging into a Local Ethernet Segment

If your goal is transparent Layer 2 broadcast bridging (for instance, linking virtual machine taps or physical NICs together), attach l2tpeth0 to an existing Linux software bridge (e.g., br0):

sudo ip link set l2tpeth0 master br0
sudo ip link set l2tpeth0 up

Step 5: Inspecting, Auditing, and Deleting Tunnels

The ip l2tp tool provides dedicated inspection subcommands to audit operational state, active sessions, and packet throughput.

To view all active tunnels and their configuration parameters:

ip l2tp show tunnel

To inspect active sessions and verify interface bindings:

ip l2tp show session

Output displays the session ID, tunnel ID, encapsulation type, interface name (l2tpeth0), and whether layer-2 sequence numbers are enabled.

Tearing Down L2TPv3 Interfaces Cleanly

When you no longer require the pseudowire, delete the session first, followed by the parent tunnel. Deleting the session automatically destroys the l2tpeth0 interface:

sudo ip l2tp del session tunnel_id 1000 session_id 1
sudo ip l2tp del tunnel tunnel_id 1000

Crucial Firewall and MTU Optimisations

To ensure uninterrupted, high-throughput traffic flow across your L2TPv3 pseudowire, keep these two critical networking nuances in mind:

  • Firewall UDP Rules: If Host A or Host B runs ufw or nftables, ensure that incoming traffic on UDP port 5000 is explicitly permitted:
    sudo ufw allow 5000/udp
  • MTU Clamping and Packet Fragmentation: L2TPv3 encapsulation adds 40 to 54 bytes of IP and UDP headers to every packet. If the underlying transport network uses a standard MTU of 1500 bytes, sending full-size 1500-byte Ethernet frames over l2tpeth0 will cause packet fragmentation. Lower the pseudowire MTU to prevent packet truncation:
    sudo ip link set l2tpeth0 mtu 1440

Get the best tech tips delivered straight to your inbox.

Join thousands of readers mastering Apple, Google, Microsoft, and Linux.