mirror of https://gitee.com/openkylin/linux.git
170 lines
7.3 KiB
Plaintext
170 lines
7.3 KiB
Plaintext
This brief document describes how to use the kernel's PPPoL2TP driver
|
|
to provide L2TP functionality. L2TP is a protocol that tunnels one or
|
|
more PPP sessions over a UDP tunnel. It is commonly used for VPNs
|
|
(L2TP/IPSec) and by ISPs to tunnel subscriber PPP sessions over an IP
|
|
network infrastructure.
|
|
|
|
Design
|
|
======
|
|
|
|
The PPPoL2TP driver, drivers/net/pppol2tp.c, provides a mechanism by
|
|
which PPP frames carried through an L2TP session are passed through
|
|
the kernel's PPP subsystem. The standard PPP daemon, pppd, handles all
|
|
PPP interaction with the peer. PPP network interfaces are created for
|
|
each local PPP endpoint.
|
|
|
|
The L2TP protocol http://www.faqs.org/rfcs/rfc2661.html defines L2TP
|
|
control and data frames. L2TP control frames carry messages between
|
|
L2TP clients/servers and are used to setup / teardown tunnels and
|
|
sessions. An L2TP client or server is implemented in userspace and
|
|
will use a regular UDP socket per tunnel. L2TP data frames carry PPP
|
|
frames, which may be PPP control or PPP data. The kernel's PPP
|
|
subsystem arranges for PPP control frames to be delivered to pppd,
|
|
while data frames are forwarded as usual.
|
|
|
|
Each tunnel and session within a tunnel is assigned a unique tunnel_id
|
|
and session_id. These ids are carried in the L2TP header of every
|
|
control and data packet. The pppol2tp driver uses them to lookup
|
|
internal tunnel and/or session contexts. Zero tunnel / session ids are
|
|
treated specially - zero ids are never assigned to tunnels or sessions
|
|
in the network. In the driver, the tunnel context keeps a pointer to
|
|
the tunnel UDP socket. The session context keeps a pointer to the
|
|
PPPoL2TP socket, as well as other data that lets the driver interface
|
|
to the kernel PPP subsystem.
|
|
|
|
Note that the pppol2tp kernel driver handles only L2TP data frames;
|
|
L2TP control frames are simply passed up to userspace in the UDP
|
|
tunnel socket. The kernel handles all datapath aspects of the
|
|
protocol, including data packet resequencing (if enabled).
|
|
|
|
There are a number of requirements on the userspace L2TP daemon in
|
|
order to use the pppol2tp driver.
|
|
|
|
1. Use a UDP socket per tunnel.
|
|
|
|
2. Create a single PPPoL2TP socket per tunnel bound to a special null
|
|
session id. This is used only for communicating with the driver but
|
|
must remain open while the tunnel is active. Opening this tunnel
|
|
management socket causes the driver to mark the tunnel socket as an
|
|
L2TP UDP encapsulation socket and flags it for use by the
|
|
referenced tunnel id. This hooks up the UDP receive path via
|
|
udp_encap_rcv() in net/ipv4/udp.c. PPP data frames are never passed
|
|
in this special PPPoX socket.
|
|
|
|
3. Create a PPPoL2TP socket per L2TP session. This is typically done
|
|
by starting pppd with the pppol2tp plugin and appropriate
|
|
arguments. A PPPoL2TP tunnel management socket (Step 2) must be
|
|
created before the first PPPoL2TP session socket is created.
|
|
|
|
When creating PPPoL2TP sockets, the application provides information
|
|
to the driver about the socket in a socket connect() call. Source and
|
|
destination tunnel and session ids are provided, as well as the file
|
|
descriptor of a UDP socket. See struct pppol2tp_addr in
|
|
include/linux/if_ppp.h. Note that zero tunnel / session ids are
|
|
treated specially. When creating the per-tunnel PPPoL2TP management
|
|
socket in Step 2 above, zero source and destination session ids are
|
|
specified, which tells the driver to prepare the supplied UDP file
|
|
descriptor for use as an L2TP tunnel socket.
|
|
|
|
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.
|
|
|
|
Only the DEBUG option is supported by the special tunnel management
|
|
PPPoX socket.
|
|
|
|
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.
|
|
|
|
Debugging
|
|
=========
|
|
|
|
The driver supports a flexible debug scheme where kernel trace
|
|
messages may be optionally enabled per tunnel and per session. Care is
|
|
needed when debugging a live system since the messages are not
|
|
rate-limited and a busy system could be swamped. Userspace uses
|
|
setsockopt on the PPPoX socket to set a debug mask.
|
|
|
|
The following debug mask bits are available:
|
|
|
|
PPPOL2TP_MSG_DEBUG verbose debug (if compiled in)
|
|
PPPOL2TP_MSG_CONTROL userspace - kernel interface
|
|
PPPOL2TP_MSG_SEQ sequence numbers handling
|
|
PPPOL2TP_MSG_DATA data packets
|
|
|
|
Sample Userspace Code
|
|
=====================
|
|
|
|
1. Create tunnel management PPPoX socket
|
|
|
|
kernel_fd = socket(AF_PPPOX, SOCK_DGRAM, PX_PROTO_OL2TP);
|
|
if (kernel_fd >= 0) {
|
|
struct sockaddr_pppol2tp sax;
|
|
struct sockaddr_in const *peer_addr;
|
|
|
|
peer_addr = l2tp_tunnel_get_peer_addr(tunnel);
|
|
memset(&sax, 0, sizeof(sax));
|
|
sax.sa_family = AF_PPPOX;
|
|
sax.sa_protocol = PX_PROTO_OL2TP;
|
|
sax.pppol2tp.fd = udp_fd; /* fd of tunnel UDP socket */
|
|
sax.pppol2tp.addr.sin_addr.s_addr = peer_addr->sin_addr.s_addr;
|
|
sax.pppol2tp.addr.sin_port = peer_addr->sin_port;
|
|
sax.pppol2tp.addr.sin_family = AF_INET;
|
|
sax.pppol2tp.s_tunnel = tunnel_id;
|
|
sax.pppol2tp.s_session = 0; /* special case: mgmt socket */
|
|
sax.pppol2tp.d_tunnel = 0;
|
|
sax.pppol2tp.d_session = 0; /* special case: mgmt socket */
|
|
|
|
if(connect(kernel_fd, (struct sockaddr *)&sax, sizeof(sax) ) < 0 ) {
|
|
perror("connect failed");
|
|
result = -errno;
|
|
goto err;
|
|
}
|
|
}
|
|
|
|
2. Create session PPPoX data socket
|
|
|
|
struct sockaddr_pppol2tp sax;
|
|
int fd;
|
|
|
|
/* Note, the target socket must be bound already, else it will not be ready */
|
|
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 socket.
|
|
*/
|
|
fd = connect(session_fd, (struct sockaddr *)&sax, sizeof(sax));
|
|
if (fd < 0 ) {
|
|
return -errno;
|
|
}
|
|
return 0;
|
|
|
|
Miscellaneous
|
|
============
|
|
|
|
The PPPoL2TP driver was developed as part of the OpenL2TP project by
|
|
Katalix Systems Ltd. OpenL2TP is a full-featured L2TP client / server,
|
|
designed from the ground up to have the L2TP datapath in the
|
|
kernel. The project also implemented the pppol2tp plugin for pppd
|
|
which allows pppd to use the kernel driver. Details can be found at
|
|
http://openl2tp.sourceforge.net.
|