| 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; |
| |
| Miscellanous |
| ============ |
| |
| 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. |