mirror of
				https://git.kernel.org/pub/scm/linux/kernel/git/chenhuacai/linux-loongson
				synced 2025-10-27 17:58:22 +00:00 
			
		
		
		
	 58e50a904e
			
		
	
	
		58e50a904e
		
	
	
	
	
		
			
			Signed-off-by: James Chapman <jchapman@katalix.com> Signed-off-by: David S. Miller <davem@davemloft.net>
		
			
				
	
	
		
			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;
 | |
| 
 | |
| 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.
 |