L2TPv3 on Linux / OpenWRT

Preface

Imagine, being able to connect to the same network, that You use at home. Not just to browse the web with the same public IP, but to BE there, and see all the other devices, that You normally have in home - that is, being in the same broadcast domain! Extending L2 connectivity beyond the physical connections is also called pseudowire. You could play multiplayer LAN games - some of them support multiplayer only in one broadcast domain. You could use netflix, without triggering their “This device isn’t part of your Netflix Household” that I described in the previous article.

L2TPv3

L2TPv3 is a protocol which allows to tunnel L2 connectivity, within either IP or UDP packet. In that way, if there is an IP connectivity between two points, L2TPv3 tunnel can be created between them! UDP encapsulation in more frequently used, since it’s a better choice with networks that use firewalls/NAT gateways. In addition, to create secure IP connectivity between two hosts, setting a VPN is required. In simplest, two hosts scenario it can even be point to point setup, with /30 CIDR - since role of the connection is to protect the L2TPv3, which doesn’t provide security at all. In my setup, I use wireguard VPN. Moreover, through L2TPv3 tunnel, multiple VLANs - trunk can be passed.

L2TPv3 in Linux

In linux, we can create the unmanaged L2TPv3 tunnels, with the following command,

1
ip l2tp add tunnel tunnel_id $LOCAL_TUNNEL_ID peer_tunnel_id $REMOTE_TUNNEL_ID encap [ip/udp] local $LOCAL_IP remote $REMOTE_IP udp_sport $LOCAL_PORT udp_dport $REMOTE_PORT

where the Local tunnel ID, and remote party’s local tunnel IP should be chosen, as well as local port, and remote party’s port. On the other side of the tunnel, setup should be done in a similar way, but local and remote party setting is swapped. To finally create an interface, a session should be created with the following command

1
ip l2tp add session tunnel_id $LOCAL_TUNNEL_ID session_id $LOCAL_SESSION_ID peer_session_id $REMOTE_SESSION_ID

where the local tunnel id should correspond to the one defined previously. On the other side of the connection, local session id and remote session id should be swapped.

After creating L2TP session, l2tpeth0 network interface is going to be created in the system. To change it’s name, the following command can be used:

1
ip link set l2tpeth0 name $LOCAL_L2TPv3_IF_NAME

Note, that to start L2TP connectivity, interface has to be up at both ends of the tunnel.

1
ip link set $LOCAL_L2TPv3_IF_NAME up

OpenWRT remarks

To run ip l2tp ... you have to install package ip-full, but to support L2TP itself, corresponding packages should also be installed kmod-l2tp, kmod-l2tp-eth and the kmod-l2tp-ip. In order to keep L2TPv3 tunnel and session always on, AFTER the Lan interface goes up, following script can be created, inside the /etc/hotplug.d/iface/99-l2tp-0, where 99-l2tp-0 is name of my choice. Below quick example of the script, used by me, to create l2tp tunnel and session always, after bootup AND lan interface bring-up.

#!/bin/sh

LOCAL_L2TPv3_IF_NAME=l2tpeth101
L2TPv3_ENCAP=udp

LOCAL_IP=10.x.x.1
LOCAL_PORT=5000
LOCAL_TUNNEL_ID=10
LOCAL_SESSION_ID=1

REMOTE_IP=10.x.x.2
REMOTE_PORT=5001
REMOTE_TUNNEL_ID=11
REMOTE_SESSION_ID=2


if [ "$ACTION" = "ifup" ] && [ "$INTERFACE" = "lan" ]; then
    logger -t l2tp "Creating L2TP tunnel for interface: $INTERFACE"
    ip l2tp add tunnel tunnel_id $LOCAL_TUNNEL_ID peer_tunnel_id $REMOTE_TUNNEL_ID encap $L2TPv3_ENCAP local $LOCAL_IP remote $REMOTE_IP udp_sport $LOCAL_PORT udp_dport $REMOTE_PORT
    ip l2tp add session tunnel_id $LOCAL_TUNNEL_ID session_id $LOCAL_SESSION_ID peer_session_id $REMOTE_SESSION_ID
    ip link set l2tpeth0 name $LOCAL_L2TPv3_IF_NAME
    ip link set $LOCAL_L2TPv3_IF_NAME up
fi