801 lines
30 KiB
ReStructuredText
801 lines
30 KiB
ReStructuredText
.. SPDX-License-Identifier: GPL-2.0
|
|
|
|
====
|
|
L2TP
|
|
====
|
|
|
|
Layer 2 Tunneling Protocol (L2TP) allows L2 frames to be tunneled over
|
|
an IP network.
|
|
|
|
This document covers the kernel's L2TP subsystem. It documents kernel
|
|
APIs for application developers who want to use the L2TP subsystem and
|
|
it provides some technical details about the internal implementation
|
|
which may be useful to kernel developers and maintainers.
|
|
|
|
Overview
|
|
========
|
|
|
|
The kernel's L2TP subsystem implements the datapath for L2TPv2 and
|
|
L2TPv3. L2TPv2 is carried over UDP. L2TPv3 is carried over UDP or
|
|
directly over IP (protocol 115).
|
|
|
|
The L2TP RFCs define two basic kinds of L2TP packets: control packets
|
|
(the "control plane"), and data packets (the "data plane"). The kernel
|
|
deals only with data packets. The more complex control packets are
|
|
handled by user space.
|
|
|
|
An L2TP tunnel carries one or more L2TP sessions. Each tunnel is
|
|
associated with a socket. Each session is associated with a virtual
|
|
netdevice, e.g. ``pppN``, ``l2tpethN``, through which data frames pass
|
|
to/from L2TP. Fields in the L2TP header identify the tunnel or session
|
|
and whether it is a control or data packet. When tunnels and sessions
|
|
are set up using the Linux kernel API, we're just setting up the L2TP
|
|
data path. All aspects of the control protocol are to be handled by
|
|
user space.
|
|
|
|
This split in responsibilities leads to a natural sequence of
|
|
operations when establishing tunnels and sessions. The procedure looks
|
|
like this:
|
|
|
|
1) Create a tunnel socket. Exchange L2TP control protocol messages
|
|
with the peer over that socket in order to establish a tunnel.
|
|
|
|
2) Create a tunnel context in the kernel, using information
|
|
obtained from the peer using the control protocol messages.
|
|
|
|
3) Exchange L2TP control protocol messages with the peer over the
|
|
tunnel socket in order to establish a session.
|
|
|
|
4) Create a session context in the kernel using information
|
|
obtained from the peer using the control protocol messages.
|
|
|
|
L2TP APIs
|
|
=========
|
|
|
|
This section documents each userspace API of the L2TP subsystem.
|
|
|
|
Tunnel Sockets
|
|
--------------
|
|
|
|
L2TPv2 always uses UDP. L2TPv3 may use UDP or IP encapsulation.
|
|
|
|
To create a tunnel socket for use by L2TP, the standard POSIX
|
|
socket API is used.
|
|
|
|
For example, for a tunnel using IPv4 addresses and UDP encapsulation::
|
|
|
|
int sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
|
|
|
Or for a tunnel using IPv6 addresses and IP encapsulation::
|
|
|
|
int sockfd = socket(AF_INET6, SOCK_DGRAM, IPPROTO_L2TP);
|
|
|
|
UDP socket programming doesn't need to be covered here.
|
|
|
|
IPPROTO_L2TP is an IP protocol type implemented by the kernel's L2TP
|
|
subsystem. The L2TPIP socket address is defined in struct
|
|
sockaddr_l2tpip and struct sockaddr_l2tpip6 at
|
|
`include/uapi/linux/l2tp.h`_. The address includes the L2TP tunnel
|
|
(connection) id. To use L2TP IP encapsulation, an L2TPv3 application
|
|
should bind the L2TPIP socket using the locally assigned
|
|
tunnel id. When the peer's tunnel id and IP address is known, a
|
|
connect must be done.
|
|
|
|
If the L2TP application needs to handle L2TPv3 tunnel setup requests
|
|
from peers using L2TPIP, it must open a dedicated L2TPIP
|
|
socket to listen for those requests and bind the socket using tunnel
|
|
id 0 since tunnel setup requests are addressed to tunnel id 0.
|
|
|
|
An L2TP tunnel and all of its sessions are automatically closed when
|
|
its tunnel socket is closed.
|
|
|
|
Netlink API
|
|
-----------
|
|
|
|
L2TP applications use netlink to manage L2TP tunnel and session
|
|
instances in the kernel. The L2TP netlink API is defined in
|
|
`include/uapi/linux/l2tp.h`_.
|
|
|
|
L2TP uses `Generic Netlink`_ (GENL). Several commands are defined:
|
|
Create, Delete, Modify and Get for tunnel and session
|
|
instances, e.g. ``L2TP_CMD_TUNNEL_CREATE``. The API header lists the
|
|
netlink attribute types that can be used with each command.
|
|
|
|
Tunnel and session instances are identified by a locally unique
|
|
32-bit id. L2TP tunnel ids are given by ``L2TP_ATTR_CONN_ID`` and
|
|
``L2TP_ATTR_PEER_CONN_ID`` attributes and L2TP session ids are given
|
|
by ``L2TP_ATTR_SESSION_ID`` and ``L2TP_ATTR_PEER_SESSION_ID``
|
|
attributes. If netlink is used to manage L2TPv2 tunnel and session
|
|
instances, the L2TPv2 16-bit tunnel/session id is cast to a 32-bit
|
|
value in these attributes.
|
|
|
|
In the ``L2TP_CMD_TUNNEL_CREATE`` command, ``L2TP_ATTR_FD`` tells the
|
|
kernel the tunnel socket fd being used. If not specified, the kernel
|
|
creates a kernel socket for the tunnel, using IP parameters set in
|
|
``L2TP_ATTR_IP[6]_SADDR``, ``L2TP_ATTR_IP[6]_DADDR``,
|
|
``L2TP_ATTR_UDP_SPORT``, ``L2TP_ATTR_UDP_DPORT`` attributes. Kernel
|
|
sockets are used to implement unmanaged L2TPv3 tunnels (iproute2's "ip
|
|
l2tp" commands). If ``L2TP_ATTR_FD`` is given, it must be a socket fd
|
|
that is already bound and connected. There is more information about
|
|
unmanaged tunnels later in this document.
|
|
|
|
``L2TP_CMD_TUNNEL_CREATE`` attributes:-
|
|
|
|
================== ======== ===
|
|
Attribute Required Use
|
|
================== ======== ===
|
|
CONN_ID Y Sets the tunnel (connection) id.
|
|
PEER_CONN_ID Y Sets the peer tunnel (connection) id.
|
|
PROTO_VERSION Y Protocol version. 2 or 3.
|
|
ENCAP_TYPE Y Encapsulation type: UDP or IP.
|
|
FD N Tunnel socket file descriptor.
|
|
UDP_CSUM N Enable IPv4 UDP checksums. Used only if FD is
|
|
not set.
|
|
UDP_ZERO_CSUM6_TX N Zero IPv6 UDP checksum on transmit. Used only
|
|
if FD is not set.
|
|
UDP_ZERO_CSUM6_RX N Zero IPv6 UDP checksum on receive. Used only if
|
|
FD is not set.
|
|
IP_SADDR N IPv4 source address. Used only if FD is not
|
|
set.
|
|
IP_DADDR N IPv4 destination address. Used only if FD is
|
|
not set.
|
|
UDP_SPORT N UDP source port. Used only if FD is not set.
|
|
UDP_DPORT N UDP destination port. Used only if FD is not
|
|
set.
|
|
IP6_SADDR N IPv6 source address. Used only if FD is not
|
|
set.
|
|
IP6_DADDR N IPv6 destination address. Used only if FD is
|
|
not set.
|
|
DEBUG N Debug flags.
|
|
================== ======== ===
|
|
|
|
``L2TP_CMD_TUNNEL_DESTROY`` attributes:-
|
|
|
|
================== ======== ===
|
|
Attribute Required Use
|
|
================== ======== ===
|
|
CONN_ID Y Identifies the tunnel id to be destroyed.
|
|
================== ======== ===
|
|
|
|
``L2TP_CMD_TUNNEL_MODIFY`` attributes:-
|
|
|
|
================== ======== ===
|
|
Attribute Required Use
|
|
================== ======== ===
|
|
CONN_ID Y Identifies the tunnel id to be modified.
|
|
DEBUG N Debug flags.
|
|
================== ======== ===
|
|
|
|
``L2TP_CMD_TUNNEL_GET`` attributes:-
|
|
|
|
================== ======== ===
|
|
Attribute Required Use
|
|
================== ======== ===
|
|
CONN_ID N Identifies the tunnel id to be queried.
|
|
Ignored in DUMP requests.
|
|
================== ======== ===
|
|
|
|
``L2TP_CMD_SESSION_CREATE`` attributes:-
|
|
|
|
================== ======== ===
|
|
Attribute Required Use
|
|
================== ======== ===
|
|
CONN_ID Y The parent tunnel id.
|
|
SESSION_ID Y Sets the session id.
|
|
PEER_SESSION_ID Y Sets the parent session id.
|
|
PW_TYPE Y Sets the pseudowire type.
|
|
DEBUG N Debug flags.
|
|
RECV_SEQ N Enable rx data sequence numbers.
|
|
SEND_SEQ N Enable tx data sequence numbers.
|
|
LNS_MODE N Enable LNS mode (auto-enable data sequence
|
|
numbers).
|
|
RECV_TIMEOUT N Timeout to wait when reordering received
|
|
packets.
|
|
L2SPEC_TYPE N Sets layer2-specific-sublayer type (L2TPv3
|
|
only).
|
|
COOKIE N Sets optional cookie (L2TPv3 only).
|
|
PEER_COOKIE N Sets optional peer cookie (L2TPv3 only).
|
|
IFNAME N Sets interface name (L2TPv3 only).
|
|
================== ======== ===
|
|
|
|
For Ethernet session types, this will create an l2tpeth virtual
|
|
interface which can then be configured as required. For PPP session
|
|
types, a PPPoL2TP socket must also be opened and connected, mapping it
|
|
onto the new session. This is covered in "PPPoL2TP Sockets" later.
|
|
|
|
``L2TP_CMD_SESSION_DESTROY`` attributes:-
|
|
|
|
================== ======== ===
|
|
Attribute Required Use
|
|
================== ======== ===
|
|
CONN_ID Y Identifies the parent tunnel id of the session
|
|
to be destroyed.
|
|
SESSION_ID Y Identifies the session id to be destroyed.
|
|
IFNAME N Identifies the session by interface name. If
|
|
set, this overrides any CONN_ID and SESSION_ID
|
|
attributes. Currently supported for L2TPv3
|
|
Ethernet sessions only.
|
|
================== ======== ===
|
|
|
|
``L2TP_CMD_SESSION_MODIFY`` attributes:-
|
|
|
|
================== ======== ===
|
|
Attribute Required Use
|
|
================== ======== ===
|
|
CONN_ID Y Identifies the parent tunnel id of the session
|
|
to be modified.
|
|
SESSION_ID Y Identifies the session id to be modified.
|
|
IFNAME N Identifies the session by interface name. If
|
|
set, this overrides any CONN_ID and SESSION_ID
|
|
attributes. Currently supported for L2TPv3
|
|
Ethernet sessions only.
|
|
DEBUG N Debug flags.
|
|
RECV_SEQ N Enable rx data sequence numbers.
|
|
SEND_SEQ N Enable tx data sequence numbers.
|
|
LNS_MODE N Enable LNS mode (auto-enable data sequence
|
|
numbers).
|
|
RECV_TIMEOUT N Timeout to wait when reordering received
|
|
packets.
|
|
================== ======== ===
|
|
|
|
``L2TP_CMD_SESSION_GET`` attributes:-
|
|
|
|
================== ======== ===
|
|
Attribute Required Use
|
|
================== ======== ===
|
|
CONN_ID N Identifies the tunnel id to be queried.
|
|
Ignored for DUMP requests.
|
|
SESSION_ID N Identifies the session id to be queried.
|
|
Ignored for DUMP requests.
|
|
IFNAME N Identifies the session by interface name.
|
|
If set, this overrides any CONN_ID and
|
|
SESSION_ID attributes. Ignored for DUMP
|
|
requests. Currently supported for L2TPv3
|
|
Ethernet sessions only.
|
|
================== ======== ===
|
|
|
|
Application developers should refer to `include/uapi/linux/l2tp.h`_ for
|
|
netlink command and attribute definitions.
|
|
|
|
Sample userspace code using libmnl_:
|
|
|
|
- Open L2TP netlink socket::
|
|
|
|
struct nl_sock *nl_sock;
|
|
int l2tp_nl_family_id;
|
|
|
|
nl_sock = nl_socket_alloc();
|
|
genl_connect(nl_sock);
|
|
genl_id = genl_ctrl_resolve(nl_sock, L2TP_GENL_NAME);
|
|
|
|
- Create a tunnel::
|
|
|
|
struct nlmsghdr *nlh;
|
|
struct genlmsghdr *gnlh;
|
|
|
|
nlh = mnl_nlmsg_put_header(buf);
|
|
nlh->nlmsg_type = genl_id; /* assigned to genl socket */
|
|
nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
|
|
nlh->nlmsg_seq = seq;
|
|
|
|
gnlh = mnl_nlmsg_put_extra_header(nlh, sizeof(*gnlh));
|
|
gnlh->cmd = L2TP_CMD_TUNNEL_CREATE;
|
|
gnlh->version = L2TP_GENL_VERSION;
|
|
gnlh->reserved = 0;
|
|
|
|
mnl_attr_put_u32(nlh, L2TP_ATTR_FD, tunl_sock_fd);
|
|
mnl_attr_put_u32(nlh, L2TP_ATTR_CONN_ID, tid);
|
|
mnl_attr_put_u32(nlh, L2TP_ATTR_PEER_CONN_ID, peer_tid);
|
|
mnl_attr_put_u8(nlh, L2TP_ATTR_PROTO_VERSION, protocol_version);
|
|
mnl_attr_put_u16(nlh, L2TP_ATTR_ENCAP_TYPE, encap);
|
|
|
|
- Create a session::
|
|
|
|
struct nlmsghdr *nlh;
|
|
struct genlmsghdr *gnlh;
|
|
|
|
nlh = mnl_nlmsg_put_header(buf);
|
|
nlh->nlmsg_type = genl_id; /* assigned to genl socket */
|
|
nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
|
|
nlh->nlmsg_seq = seq;
|
|
|
|
gnlh = mnl_nlmsg_put_extra_header(nlh, sizeof(*gnlh));
|
|
gnlh->cmd = L2TP_CMD_SESSION_CREATE;
|
|
gnlh->version = L2TP_GENL_VERSION;
|
|
gnlh->reserved = 0;
|
|
|
|
mnl_attr_put_u32(nlh, L2TP_ATTR_CONN_ID, tid);
|
|
mnl_attr_put_u32(nlh, L2TP_ATTR_PEER_CONN_ID, peer_tid);
|
|
mnl_attr_put_u32(nlh, L2TP_ATTR_SESSION_ID, sid);
|
|
mnl_attr_put_u32(nlh, L2TP_ATTR_PEER_SESSION_ID, peer_sid);
|
|
mnl_attr_put_u16(nlh, L2TP_ATTR_PW_TYPE, pwtype);
|
|
/* there are other session options which can be set using netlink
|
|
* attributes during session creation -- see l2tp.h
|
|
*/
|
|
|
|
- Delete a session::
|
|
|
|
struct nlmsghdr *nlh;
|
|
struct genlmsghdr *gnlh;
|
|
|
|
nlh = mnl_nlmsg_put_header(buf);
|
|
nlh->nlmsg_type = genl_id; /* assigned to genl socket */
|
|
nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
|
|
nlh->nlmsg_seq = seq;
|
|
|
|
gnlh = mnl_nlmsg_put_extra_header(nlh, sizeof(*gnlh));
|
|
gnlh->cmd = L2TP_CMD_SESSION_DELETE;
|
|
gnlh->version = L2TP_GENL_VERSION;
|
|
gnlh->reserved = 0;
|
|
|
|
mnl_attr_put_u32(nlh, L2TP_ATTR_CONN_ID, tid);
|
|
mnl_attr_put_u32(nlh, L2TP_ATTR_SESSION_ID, sid);
|
|
|
|
- Delete a tunnel and all of its sessions (if any)::
|
|
|
|
struct nlmsghdr *nlh;
|
|
struct genlmsghdr *gnlh;
|
|
|
|
nlh = mnl_nlmsg_put_header(buf);
|
|
nlh->nlmsg_type = genl_id; /* assigned to genl socket */
|
|
nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
|
|
nlh->nlmsg_seq = seq;
|
|
|
|
gnlh = mnl_nlmsg_put_extra_header(nlh, sizeof(*gnlh));
|
|
gnlh->cmd = L2TP_CMD_TUNNEL_DELETE;
|
|
gnlh->version = L2TP_GENL_VERSION;
|
|
gnlh->reserved = 0;
|
|
|
|
mnl_attr_put_u32(nlh, L2TP_ATTR_CONN_ID, tid);
|
|
|
|
PPPoL2TP Session Socket API
|
|
---------------------------
|
|
|
|
For PPP session types, a PPPoL2TP socket must be opened and connected
|
|
to the L2TP session.
|
|
|
|
When creating PPPoL2TP sockets, the application provides information
|
|
to the kernel about the tunnel and session in a socket connect()
|
|
call. Source and destination tunnel and session ids are provided, as
|
|
well as the file descriptor of a UDP or L2TPIP socket. See struct
|
|
pppol2tp_addr in `include/linux/if_pppol2tp.h`_. For historical reasons,
|
|
there are unfortunately slightly different address structures for
|
|
L2TPv2/L2TPv3 IPv4/IPv6 tunnels and userspace must use the appropriate
|
|
structure that matches the tunnel socket type.
|
|
|
|
Userspace may control behavior of the tunnel or session using
|
|
setsockopt and ioctl on the PPPoX socket. The following socket
|
|
options are supported:-
|
|
|
|
========= ===========================================================
|
|
DEBUG bitmask of debug message categories. See below.
|
|
SENDSEQ - 0 => don't send packets with sequence numbers
|
|
- 1 => send packets with sequence numbers
|
|
RECVSEQ - 0 => receive packet sequence numbers are optional
|
|
- 1 => drop receive packets without sequence numbers
|
|
LNSMODE - 0 => act as LAC.
|
|
- 1 => act as LNS.
|
|
REORDERTO reorder timeout (in millisecs). If 0, don't try to reorder.
|
|
========= ===========================================================
|
|
|
|
In addition to the standard PPP ioctls, a PPPIOCGL2TPSTATS is provided
|
|
to retrieve tunnel and session statistics from the kernel using the
|
|
PPPoX socket of the appropriate tunnel or session.
|
|
|
|
Sample userspace code:
|
|
|
|
- Create session PPPoX data socket::
|
|
|
|
/* Input: the L2TP tunnel UDP socket `tunnel_fd`, which needs to be
|
|
* bound already (both sockname and peername), otherwise it will not be
|
|
* ready.
|
|
*/
|
|
|
|
struct sockaddr_pppol2tp sax;
|
|
int session_fd;
|
|
int ret;
|
|
|
|
session_fd = socket(AF_PPPOX, SOCK_DGRAM, PX_PROTO_OL2TP);
|
|
if (session_fd < 0)
|
|
return -errno;
|
|
|
|
sax.sa_family = AF_PPPOX;
|
|
sax.sa_protocol = PX_PROTO_OL2TP;
|
|
sax.pppol2tp.fd = tunnel_fd;
|
|
sax.pppol2tp.addr.sin_addr.s_addr = addr->sin_addr.s_addr;
|
|
sax.pppol2tp.addr.sin_port = addr->sin_port;
|
|
sax.pppol2tp.addr.sin_family = AF_INET;
|
|
sax.pppol2tp.s_tunnel = tunnel_id;
|
|
sax.pppol2tp.s_session = session_id;
|
|
sax.pppol2tp.d_tunnel = peer_tunnel_id;
|
|
sax.pppol2tp.d_session = peer_session_id;
|
|
|
|
/* session_fd is the fd of the session's PPPoL2TP socket.
|
|
* tunnel_fd is the fd of the tunnel UDP / L2TPIP socket.
|
|
*/
|
|
ret = connect(session_fd, (struct sockaddr *)&sax, sizeof(sax));
|
|
if (ret < 0 ) {
|
|
close(session_fd);
|
|
return -errno;
|
|
}
|
|
|
|
return session_fd;
|
|
|
|
L2TP control packets will still be available for read on `tunnel_fd`.
|
|
|
|
- Create PPP channel::
|
|
|
|
/* Input: the session PPPoX data socket `session_fd` which was created
|
|
* as described above.
|
|
*/
|
|
|
|
int ppp_chan_fd;
|
|
int chindx;
|
|
int ret;
|
|
|
|
ret = ioctl(session_fd, PPPIOCGCHAN, &chindx);
|
|
if (ret < 0)
|
|
return -errno;
|
|
|
|
ppp_chan_fd = open("/dev/ppp", O_RDWR);
|
|
if (ppp_chan_fd < 0)
|
|
return -errno;
|
|
|
|
ret = ioctl(ppp_chan_fd, PPPIOCATTCHAN, &chindx);
|
|
if (ret < 0) {
|
|
close(ppp_chan_fd);
|
|
return -errno;
|
|
}
|
|
|
|
return ppp_chan_fd;
|
|
|
|
LCP PPP frames will be available for read on `ppp_chan_fd`.
|
|
|
|
- Create PPP interface::
|
|
|
|
/* Input: the PPP channel `ppp_chan_fd` which was created as described
|
|
* above.
|
|
*/
|
|
|
|
int ifunit = -1;
|
|
int ppp_if_fd;
|
|
int ret;
|
|
|
|
ppp_if_fd = open("/dev/ppp", O_RDWR);
|
|
if (ppp_if_fd < 0)
|
|
return -errno;
|
|
|
|
ret = ioctl(ppp_if_fd, PPPIOCNEWUNIT, &ifunit);
|
|
if (ret < 0) {
|
|
close(ppp_if_fd);
|
|
return -errno;
|
|
}
|
|
|
|
ret = ioctl(ppp_chan_fd, PPPIOCCONNECT, &ifunit);
|
|
if (ret < 0) {
|
|
close(ppp_if_fd);
|
|
return -errno;
|
|
}
|
|
|
|
return ppp_if_fd;
|
|
|
|
IPCP/IPv6CP PPP frames will be available for read on `ppp_if_fd`.
|
|
|
|
The ppp<ifunit> interface can then be configured as usual with netlink's
|
|
RTM_NEWLINK, RTM_NEWADDR, RTM_NEWROUTE, or ioctl's SIOCSIFMTU, SIOCSIFADDR,
|
|
SIOCSIFDSTADDR, SIOCSIFNETMASK, SIOCSIFFLAGS, or with the `ip` command.
|
|
|
|
- Bridging L2TP sessions which have PPP pseudowire types (this is also called
|
|
L2TP tunnel switching or L2TP multihop) is supported by bridging the PPP
|
|
channels of the two L2TP sessions to be bridged::
|
|
|
|
/* Input: the session PPPoX data sockets `session_fd1` and `session_fd2`
|
|
* which were created as described further above.
|
|
*/
|
|
|
|
int ppp_chan_fd;
|
|
int chindx1;
|
|
int chindx2;
|
|
int ret;
|
|
|
|
ret = ioctl(session_fd1, PPPIOCGCHAN, &chindx1);
|
|
if (ret < 0)
|
|
return -errno;
|
|
|
|
ret = ioctl(session_fd2, PPPIOCGCHAN, &chindx2);
|
|
if (ret < 0)
|
|
return -errno;
|
|
|
|
ppp_chan_fd = open("/dev/ppp", O_RDWR);
|
|
if (ppp_chan_fd < 0)
|
|
return -errno;
|
|
|
|
ret = ioctl(ppp_chan_fd, PPPIOCATTCHAN, &chindx1);
|
|
if (ret < 0) {
|
|
close(ppp_chan_fd);
|
|
return -errno;
|
|
}
|
|
|
|
ret = ioctl(ppp_chan_fd, PPPIOCBRIDGECHAN, &chindx2);
|
|
close(ppp_chan_fd);
|
|
if (ret < 0)
|
|
return -errno;
|
|
|
|
return 0;
|
|
|
|
It can be noted that when bridging PPP channels, the PPP session is not locally
|
|
terminated, and no local PPP interface is created. PPP frames arriving on one
|
|
channel are directly passed to the other channel, and vice versa.
|
|
|
|
The PPP channel does not need to be kept open. Only the session PPPoX data
|
|
sockets need to be kept open.
|
|
|
|
More generally, it is also possible in the same way to e.g. bridge a PPPoL2TP
|
|
PPP channel with other types of PPP channels, such as PPPoE.
|
|
|
|
See more details for the PPP side in ppp_generic.rst.
|
|
|
|
Old L2TPv2-only API
|
|
-------------------
|
|
|
|
When L2TP was first added to the Linux kernel in 2.6.23, it
|
|
implemented only L2TPv2 and did not include a netlink API. Instead,
|
|
tunnel and session instances in the kernel were managed directly using
|
|
only PPPoL2TP sockets. The PPPoL2TP socket is used as described in
|
|
section "PPPoL2TP Session Socket API" but tunnel and session instances
|
|
are automatically created on a connect() of the socket instead of
|
|
being created by a separate netlink request:
|
|
|
|
- Tunnels are managed using a tunnel management socket which is a
|
|
dedicated PPPoL2TP socket, connected to (invalid) session
|
|
id 0. The L2TP tunnel instance is created when the PPPoL2TP
|
|
tunnel management socket is connected and is destroyed when the
|
|
socket is closed.
|
|
|
|
- Session instances are created in the kernel when a PPPoL2TP
|
|
socket is connected to a non-zero session id. Session parameters
|
|
are set using setsockopt. The L2TP session instance is destroyed
|
|
when the socket is closed.
|
|
|
|
This API is still supported but its use is discouraged. Instead, new
|
|
L2TPv2 applications should use netlink to first create the tunnel and
|
|
session, then create a PPPoL2TP socket for the session.
|
|
|
|
Unmanaged L2TPv3 tunnels
|
|
------------------------
|
|
|
|
The kernel L2TP subsystem also supports static (unmanaged) L2TPv3
|
|
tunnels. Unmanaged tunnels have no userspace tunnel socket, and
|
|
exchange no control messages with the peer to set up the tunnel; the
|
|
tunnel is configured manually at each end of the tunnel. All
|
|
configuration is done using netlink. There is no need for an L2TP
|
|
userspace application in this case -- the tunnel socket is created by
|
|
the kernel and configured using parameters sent in the
|
|
``L2TP_CMD_TUNNEL_CREATE`` netlink request. The ``ip`` utility of
|
|
``iproute2`` has commands for managing static L2TPv3 tunnels; do ``ip
|
|
l2tp help`` for more information.
|
|
|
|
Debugging
|
|
---------
|
|
|
|
The L2TP subsystem offers a range of debugging interfaces through the
|
|
debugfs filesystem.
|
|
|
|
To access these interfaces, the debugfs filesystem must first be mounted::
|
|
|
|
# mount -t debugfs debugfs /debug
|
|
|
|
Files under the l2tp directory can then be accessed, providing a summary
|
|
of the current population of tunnel and session contexts existing in the
|
|
kernel::
|
|
|
|
# cat /debug/l2tp/tunnels
|
|
|
|
The debugfs files should not be used by applications to obtain L2TP
|
|
state information because the file format is subject to change. It is
|
|
implemented to provide extra debug information to help diagnose
|
|
problems. Applications should instead use the netlink API.
|
|
|
|
In addition the L2TP subsystem implements tracepoints using the standard
|
|
kernel event tracing API. The available L2TP events can be reviewed as
|
|
follows::
|
|
|
|
# find /debug/tracing/events/l2tp
|
|
|
|
Finally, /proc/net/pppol2tp is also provided for backwards compatibility
|
|
with the original pppol2tp code. It lists information about L2TPv2
|
|
tunnels and sessions only. Its use is discouraged.
|
|
|
|
Internal Implementation
|
|
=======================
|
|
|
|
This section is for kernel developers and maintainers.
|
|
|
|
Sockets
|
|
-------
|
|
|
|
UDP sockets are implemented by the networking core. When an L2TP
|
|
tunnel is created using a UDP socket, the socket is set up as an
|
|
encapsulated UDP socket by setting encap_rcv and encap_destroy
|
|
callbacks on the UDP socket. l2tp_udp_encap_recv is called when
|
|
packets are received on the socket. l2tp_udp_encap_destroy is called
|
|
when userspace closes the socket.
|
|
|
|
L2TPIP sockets are implemented in `net/l2tp/l2tp_ip.c`_ and
|
|
`net/l2tp/l2tp_ip6.c`_.
|
|
|
|
Tunnels
|
|
-------
|
|
|
|
The kernel keeps a struct l2tp_tunnel context per L2TP tunnel. The
|
|
l2tp_tunnel is always associated with a UDP or L2TP/IP socket and
|
|
keeps a list of sessions in the tunnel. When a tunnel is first
|
|
registered with L2TP core, the reference count on the socket is
|
|
increased. This ensures that the socket cannot be removed while L2TP's
|
|
data structures reference it.
|
|
|
|
Tunnels are identified by a unique tunnel id. The id is 16-bit for
|
|
L2TPv2 and 32-bit for L2TPv3. Internally, the id is stored as a 32-bit
|
|
value.
|
|
|
|
Tunnels are kept in a per-net list, indexed by tunnel id. The tunnel
|
|
id namespace is shared by L2TPv2 and L2TPv3. The tunnel context can be
|
|
derived from the socket's sk_user_data.
|
|
|
|
Handling tunnel socket close is perhaps the most tricky part of the
|
|
L2TP implementation. If userspace closes a tunnel socket, the L2TP
|
|
tunnel and all of its sessions must be closed and destroyed. Since the
|
|
tunnel context holds a ref on the tunnel socket, the socket's
|
|
sk_destruct won't be called until the tunnel sock_put's its
|
|
socket. For UDP sockets, when userspace closes the tunnel socket, the
|
|
socket's encap_destroy handler is invoked, which L2TP uses to initiate
|
|
its tunnel close actions. For L2TPIP sockets, the socket's close
|
|
handler initiates the same tunnel close actions. All sessions are
|
|
first closed. Each session drops its tunnel ref. When the tunnel ref
|
|
reaches zero, the tunnel puts its socket ref. When the socket is
|
|
eventually destroyed, its sk_destruct finally frees the L2TP tunnel
|
|
context.
|
|
|
|
Sessions
|
|
--------
|
|
|
|
The kernel keeps a struct l2tp_session context for each session. Each
|
|
session has private data which is used for data specific to the
|
|
session type. With L2TPv2, the session always carries PPP
|
|
traffic. With L2TPv3, the session can carry Ethernet frames (Ethernet
|
|
pseudowire) or other data types such as PPP, ATM, HDLC or Frame
|
|
Relay. Linux currently implements only Ethernet and PPP session types.
|
|
|
|
Some L2TP session types also have a socket (PPP pseudowires) while
|
|
others do not (Ethernet pseudowires). We can't therefore use the
|
|
socket reference count as the reference count for session
|
|
contexts. The L2TP implementation therefore has its own internal
|
|
reference counts on the session contexts.
|
|
|
|
Like tunnels, L2TP sessions are identified by a unique
|
|
session id. Just as with tunnel ids, the session id is 16-bit for
|
|
L2TPv2 and 32-bit for L2TPv3. Internally, the id is stored as a 32-bit
|
|
value.
|
|
|
|
Sessions hold a ref on their parent tunnel to ensure that the tunnel
|
|
stays extant while one or more sessions references it.
|
|
|
|
Sessions are kept in a per-tunnel list, indexed by session id. L2TPv3
|
|
sessions are also kept in a per-net list indexed by session id,
|
|
because L2TPv3 session ids are unique across all tunnels and L2TPv3
|
|
data packets do not contain a tunnel id in the header. This list is
|
|
therefore needed to find the session context associated with a
|
|
received data packet when the tunnel context cannot be derived from
|
|
the tunnel socket.
|
|
|
|
Although the L2TPv3 RFC specifies that L2TPv3 session ids are not
|
|
scoped by the tunnel, the kernel does not police this for L2TPv3 UDP
|
|
tunnels and does not add sessions of L2TPv3 UDP tunnels into the
|
|
per-net session list. In the UDP receive code, we must trust that the
|
|
tunnel can be identified using the tunnel socket's sk_user_data and
|
|
lookup the session in the tunnel's session list instead of the per-net
|
|
session list.
|
|
|
|
PPP
|
|
---
|
|
|
|
`net/l2tp/l2tp_ppp.c`_ implements the PPPoL2TP socket family. Each PPP
|
|
session has a PPPoL2TP socket.
|
|
|
|
The PPPoL2TP socket's sk_user_data references the l2tp_session.
|
|
|
|
Userspace sends and receives PPP packets over L2TP using a PPPoL2TP
|
|
socket. Only PPP control frames pass over this socket: PPP data
|
|
packets are handled entirely by the kernel, passing between the L2TP
|
|
session and its associated ``pppN`` netdev through the PPP channel
|
|
interface of the kernel PPP subsystem.
|
|
|
|
The L2TP PPP implementation handles the closing of a PPPoL2TP socket
|
|
by closing its corresponding L2TP session. This is complicated because
|
|
it must consider racing with netlink session create/destroy requests
|
|
and pppol2tp_connect trying to reconnect with a session that is in the
|
|
process of being closed. Unlike tunnels, PPP sessions do not hold a
|
|
ref on their associated socket, so code must be careful to sock_hold
|
|
the socket where necessary. For all the details, see commit
|
|
3d609342cc04129ff7568e19316ce3d7451a27e8.
|
|
|
|
Ethernet
|
|
--------
|
|
|
|
`net/l2tp/l2tp_eth.c`_ implements L2TPv3 Ethernet pseudowires. It
|
|
manages a netdev for each session.
|
|
|
|
L2TP Ethernet sessions are created and destroyed by netlink request,
|
|
or are destroyed when the tunnel is destroyed. Unlike PPP sessions,
|
|
Ethernet sessions do not have an associated socket.
|
|
|
|
Miscellaneous
|
|
=============
|
|
|
|
RFCs
|
|
----
|
|
|
|
The kernel code implements the datapath features specified in the
|
|
following RFCs:
|
|
|
|
======= =============== ===================================
|
|
RFC2661 L2TPv2 https://tools.ietf.org/html/rfc2661
|
|
RFC3931 L2TPv3 https://tools.ietf.org/html/rfc3931
|
|
RFC4719 L2TPv3 Ethernet https://tools.ietf.org/html/rfc4719
|
|
======= =============== ===================================
|
|
|
|
Implementations
|
|
---------------
|
|
|
|
A number of open source applications use the L2TP kernel subsystem:
|
|
|
|
============ ==============================================
|
|
iproute2 https://github.com/shemminger/iproute2
|
|
go-l2tp https://github.com/katalix/go-l2tp
|
|
tunneldigger https://github.com/wlanslovenija/tunneldigger
|
|
xl2tpd https://github.com/xelerance/xl2tpd
|
|
============ ==============================================
|
|
|
|
Limitations
|
|
-----------
|
|
|
|
The current implementation has a number of limitations:
|
|
|
|
1) Multiple UDP sockets with the same 5-tuple address cannot be
|
|
used. The kernel's tunnel context is identified using private
|
|
data associated with the socket so it is important that each
|
|
socket is uniquely identified by its address.
|
|
|
|
2) Interfacing with openvswitch is not yet implemented. It may be
|
|
useful to map OVS Ethernet and VLAN ports into L2TPv3 tunnels.
|
|
|
|
3) VLAN pseudowires are implemented using an ``l2tpethN`` interface
|
|
configured with a VLAN sub-interface. Since L2TPv3 VLAN
|
|
pseudowires carry one and only one VLAN, it may be better to use
|
|
a single netdevice rather than an ``l2tpethN`` and ``l2tpethN``:M
|
|
pair per VLAN session. The netlink attribute
|
|
``L2TP_ATTR_VLAN_ID`` was added for this, but it was never
|
|
implemented.
|
|
|
|
Testing
|
|
-------
|
|
|
|
Unmanaged L2TPv3 Ethernet features are tested by the kernel's built-in
|
|
selftests. See `tools/testing/selftests/net/l2tp.sh`_.
|
|
|
|
Another test suite, l2tp-ktest_, covers all
|
|
of the L2TP APIs and tunnel/session types. This may be integrated into
|
|
the kernel's built-in L2TP selftests in the future.
|
|
|
|
.. Links
|
|
.. _Generic Netlink: generic_netlink.html
|
|
.. _libmnl: https://www.netfilter.org/projects/libmnl
|
|
.. _include/uapi/linux/l2tp.h: ../../../include/uapi/linux/l2tp.h
|
|
.. _include/linux/if_pppol2tp.h: ../../../include/linux/if_pppol2tp.h
|
|
.. _net/l2tp/l2tp_ip.c: ../../../net/l2tp/l2tp_ip.c
|
|
.. _net/l2tp/l2tp_ip6.c: ../../../net/l2tp/l2tp_ip6.c
|
|
.. _net/l2tp/l2tp_ppp.c: ../../../net/l2tp/l2tp_ppp.c
|
|
.. _net/l2tp/l2tp_eth.c: ../../../net/l2tp/l2tp_eth.c
|
|
.. _tools/testing/selftests/net/l2tp.sh: ../../../tools/testing/selftests/net/l2tp.sh
|
|
.. _l2tp-ktest: https://github.com/katalix/l2tp-ktest
|