Subject: [PATCH net-next 0/8] l2tp: don't use the tunnel socket's sk_user_data in datapath

From: James Chapman <[email-masked]>
Date: Thu, 20 Jun 2024 12:22:36 +0100

This series refactors l2tp to not use the tunnel socket's sk_user_data
in the datapath. The main reasons for doing this are

 * to allow for simplifying internal socket cleanup code (to be done
   in a later series)
 * to support multiple L2TPv3 UDP tunnels using the same 5-tuple
   address

When handling received UDP frames, l2tp's current approach is to look
up a session in a per-tunnel list. l2tp uses the tunnel socket's
sk_user_data to derive the tunnel context from the receiving socket.

But this results in the socket and tunnel lifetimes being very tightly
coupled and the tunnel/socket cleanup paths being complicated. The
latter has historically been a source of l2tp bugs and makes the code
more difficult to maintain. Also, if sockets are aliased, we can't
trust that the socket's sk_user_data references the right tunnel
anyway. Hence the desire to not use sk_user_data in the datapath.

The new approach is to lookup sessions in a per-net session list
without first deriving the tunnel:

 * For L2TPv2, the l2tp header has separate tunnel ID and session ID
   fields which can be trivially combined to make a unique 32-bit key
   for per-net session lookup.

 * For L2TPv3, there is no tunnel ID in the packet header, only a
   session ID, which should be unique over all tunnels so can be used
   as a key for per-net session lookup. However, this only works when
   the L2TPv3 session ID really is unique over all tunnels. At least
   one L2TPv3 application is known to use the same session ID in
   different L2TPv3 UDP tunnels, relying on UDP address/ports to
   distinguish them. This worked previously because sessions in UDP
   tunnels were kept in a per-tunnel list. To retain support for this,
   L2TPv3 session ID collisions are managed using a separate per-net
   session hlist, keyed by ID and sk. When looking up a session by ID,
   if there's more than one match, sk is used to find the right one.

L2TPv3 sessions in IP-encap tunnels are already looked up by session
ID in a per-net list. This work has UDP sessions also use the per-net
session list, while allowing for session ID collisions. The existing
per-tunnel hlist becomes a plain list since it is used only in
management and cleanup paths to walk a list of sessions in a given
tunnel.

For better performance, the per-net session lists use IDR. Separate
IDRs are used for L2TPv2 and L2TPv3 sessions to avoid potential key
collisions.

These changes pass l2tp regression tests and improve data forwarding
performance by about 10% in some of my test setups.

James Chapman (8):
  l2tp: remove unused list_head member in l2tp_tunnel
  l2tp: store l2tpv3 sessions in per-net IDR
  l2tp: store l2tpv2 sessions in per-net IDR
  l2tp: refactor udp recv to lookup to not use sk_user_data
  l2tp: don't use sk_user_data in l2tp_udp_encap_err_recv
  l2tp: use IDR for all session lookups
  l2tp: drop the now unused l2tp_tunnel_get_session
  l2tp: replace hlist with simple list for per-tunnel session list

 net/l2tp/l2tp_core.c    | 501 ++++++++++++++++++++++------------------
 net/l2tp/l2tp_core.h    |  43 ++--
 net/l2tp/l2tp_debugfs.c |  13 +-
 net/l2tp/l2tp_ip.c      |   2 +-
 net/l2tp/l2tp_ip6.c     |   2 +-
 net/l2tp/l2tp_netlink.c |   6 +-
 net/l2tp/l2tp_ppp.c     |   6 +-
 7 files changed, 308 insertions(+), 265 deletions(-)

-- 
2.34.1