Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 27 Aug 2019 00:01:57 +0000 (UTC)
From:      John Baldwin <jhb@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r351522 - in head: sbin/ifconfig share/man/man4 sys/conf sys/kern sys/modules sys/modules/ktls_ocf sys/net sys/netinet sys/netinet/tcp_stacks sys/netinet6 sys/opencrypto sys/sys tools/t...
Message-ID:  <201908270001.x7R01vUB052426@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: jhb
Date: Tue Aug 27 00:01:56 2019
New Revision: 351522
URL: https://svnweb.freebsd.org/changeset/base/351522

Log:
  Add kernel-side support for in-kernel TLS.
  
  KTLS adds support for in-kernel framing and encryption of Transport
  Layer Security (1.0-1.2) data on TCP sockets.  KTLS only supports
  offload of TLS for transmitted data.  Key negotation must still be
  performed in userland.  Once completed, transmit session keys for a
  connection are provided to the kernel via a new TCP_TXTLS_ENABLE
  socket option.  All subsequent data transmitted on the socket is
  placed into TLS frames and encrypted using the supplied keys.
  
  Any data written to a KTLS-enabled socket via write(2), aio_write(2),
  or sendfile(2) is assumed to be application data and is encoded in TLS
  frames with an application data type.  Individual records can be sent
  with a custom type (e.g. handshake messages) via sendmsg(2) with a new
  control message (TLS_SET_RECORD_TYPE) specifying the record type.
  
  At present, rekeying is not supported though the in-kernel framework
  should support rekeying.
  
  KTLS makes use of the recently added unmapped mbufs to store TLS
  frames in the socket buffer.  Each TLS frame is described by a single
  ext_pgs mbuf.  The ext_pgs structure contains the header of the TLS
  record (and trailer for encrypted records) as well as references to
  the associated TLS session.
  
  KTLS supports two primary methods of encrypting TLS frames: software
  TLS and ifnet TLS.
  
  Software TLS marks mbufs holding socket data as not ready via
  M_NOTREADY similar to sendfile(2) when TLS framing information is
  added to an unmapped mbuf in ktls_frame().  ktls_enqueue() is then
  called to schedule TLS frames for encryption.  In the case of
  sendfile_iodone() calls ktls_enqueue() instead of pru_ready() leaving
  the mbufs marked M_NOTREADY until encryption is completed.  For other
  writes (vn_sendfile when pages are available, write(2), etc.), the
  PRUS_NOTREADY is set when invoking pru_send() along with invoking
  ktls_enqueue().
  
  A pool of worker threads (the "KTLS" kernel process) encrypts TLS
  frames queued via ktls_enqueue().  Each TLS frame is temporarily
  mapped using the direct map and passed to a software encryption
  backend to perform the actual encryption.
  
  (Note: The use of PHYS_TO_DMAP could be replaced with sf_bufs if
  someone wished to make this work on architectures without a direct
  map.)
  
  KTLS supports pluggable software encryption backends.  Internally,
  Netflix uses proprietary pure-software backends.  This commit includes
  a simple backend in a new ktls_ocf.ko module that uses the kernel's
  OpenCrypto framework to provide AES-GCM encryption of TLS frames.  As
  a result, software TLS is now a bit of a misnomer as it can make use
  of hardware crypto accelerators.
  
  Once software encryption has finished, the TLS frame mbufs are marked
  ready via pru_ready().  At this point, the encrypted data appears as
  regular payload to the TCP stack stored in unmapped mbufs.
  
  ifnet TLS permits a NIC to offload the TLS encryption and TCP
  segmentation.  In this mode, a new send tag type (IF_SND_TAG_TYPE_TLS)
  is allocated on the interface a socket is routed over and associated
  with a TLS session.  TLS records for a TLS session using ifnet TLS are
  not marked M_NOTREADY but are passed down the stack unencrypted.  The
  ip_output_send() and ip6_output_send() helper functions that apply
  send tags to outbound IP packets verify that the send tag of the TLS
  record matches the outbound interface.  If so, the packet is tagged
  with the TLS send tag and sent to the interface.  The NIC device
  driver must recognize packets with the TLS send tag and schedule them
  for TLS encryption and TCP segmentation.  If the the outbound
  interface does not match the interface in the TLS send tag, the packet
  is dropped.  In addition, a task is scheduled to refresh the TLS send
  tag for the TLS session.  If a new TLS send tag cannot be allocated,
  the connection is dropped.  If a new TLS send tag is allocated,
  however, subsequent packets will be tagged with the correct TLS send
  tag.  (This latter case has been tested by configuring both ports of a
  Chelsio T6 in a lagg and failing over from one port to another.  As
  the connections migrated to the new port, new TLS send tags were
  allocated for the new port and connections resumed without being
  dropped.)
  
  ifnet TLS can be enabled and disabled on supported network interfaces
  via new '[-]txtls[46]' options to ifconfig(8).  ifnet TLS is supported
  across both vlan devices and lagg interfaces using failover, lacp with
  flowid enabled, or lacp with flowid enabled.
  
  Applications may request the current KTLS mode of a connection via a
  new TCP_TXTLS_MODE socket option.  They can also use this socket
  option to toggle between software and ifnet TLS modes.
  
  In addition, a testing tool is available in tools/tools/switch_tls.
  This is modeled on tcpdrop and uses similar syntax.  However, instead
  of dropping connections, -s is used to force KTLS connections to
  switch to software TLS and -i is used to switch to ifnet TLS.
  
  Various sysctls and counters are available under the kern.ipc.tls
  sysctl node.  The kern.ipc.tls.enable node must be set to true to
  enable KTLS (it is off by default).  The use of unmapped mbufs must
  also be enabled via kern.ipc.mb_use_ext_pgs to enable KTLS.
  
  KTLS is enabled via the KERN_TLS kernel option.
  
  This patch is the culmination of years of work by several folks
  including Scott Long and Randall Stewart for the original design and
  implementation; Drew Gallatin for several optimizations including the
  use of ext_pgs mbufs, the M_NOTREADY mechanism for TLS records
  awaiting software encryption, and pluggable software crypto backends;
  and John Baldwin for modifications to support hardware TLS offload.
  
  Reviewed by:	gallatin, hselasky, rrs
  Obtained from:	Netflix
  Sponsored by:	Netflix, Chelsio Communications
  Differential Revision:	https://reviews.freebsd.org/D21277

Added:
  head/sys/kern/uipc_ktls.c   (contents, props changed)
  head/sys/modules/ktls_ocf/
  head/sys/modules/ktls_ocf/Makefile   (contents, props changed)
  head/sys/opencrypto/ktls_ocf.c   (contents, props changed)
  head/sys/sys/ktls.h   (contents, props changed)
  head/tools/tools/switch_tls/
  head/tools/tools/switch_tls/Makefile   (contents, props changed)
  head/tools/tools/switch_tls/switch_tls.c   (contents, props changed)
Modified:
  head/sbin/ifconfig/ifconfig.8
  head/sbin/ifconfig/ifconfig.c
  head/share/man/man4/tcp.4
  head/sys/conf/NOTES
  head/sys/conf/files
  head/sys/conf/options
  head/sys/kern/kern_mbuf.c
  head/sys/kern/kern_sendfile.c
  head/sys/kern/uipc_sockbuf.c
  head/sys/kern/uipc_socket.c
  head/sys/modules/Makefile
  head/sys/net/ieee8023ad_lacp.c
  head/sys/net/ieee8023ad_lacp.h
  head/sys/net/if.h
  head/sys/net/if_lagg.c
  head/sys/net/if_var.h
  head/sys/net/if_vlan.c
  head/sys/netinet/ip_output.c
  head/sys/netinet/tcp.h
  head/sys/netinet/tcp_output.c
  head/sys/netinet/tcp_stacks/rack.c
  head/sys/netinet/tcp_subr.c
  head/sys/netinet/tcp_usrreq.c
  head/sys/netinet/tcp_var.h
  head/sys/netinet6/ip6_output.c
  head/sys/sys/mbuf.h
  head/sys/sys/param.h
  head/sys/sys/sockbuf.h

Modified: head/sbin/ifconfig/ifconfig.8
==============================================================================
--- head/sbin/ifconfig/ifconfig.8	Mon Aug 26 21:00:14 2019	(r351521)
+++ head/sbin/ifconfig/ifconfig.8	Tue Aug 27 00:01:56 2019	(r351522)
@@ -28,7 +28,7 @@
 .\"     From: @(#)ifconfig.8	8.3 (Berkeley) 1/5/94
 .\" $FreeBSD$
 .\"
-.Dd August 15, 2019
+.Dd August 26, 2019
 .Dt IFCONFIG 8
 .Os
 .Sh NAME
@@ -538,6 +538,28 @@ large receive offloading, enable LRO on the interface.
 If the driver supports
 .Xr tcp 4
 large receive offloading, disable LRO on the interface.
+.It Cm txtls
+Transmit TLS offload encrypts Transport Layer Security (TLS) records and
+segments the encrypted record into one or more
+.Xr tcp 4
+segments over either
+.Xr ip 4
+or
+.Xr ip6 4 .
+If the driver supports transmit TLS offload,
+enable transmit TLS offload on the interface.
+Some drivers may not be able to support transmit TLS offload for
+.Xr ip 4
+and
+.Xr ip6 4
+packets, so they may enable only one of them.
+.It Fl txtls
+If the driver supports transmit TLS offload,
+disable transmit TLS offload on the interface.
+It will always disable TLS for
+.Xr ip 4
+and
+.Xr ip6 4 .
 .It Cm nomap
 If the driver supports unmapped network buffers,
 enable them on the interface.

Modified: head/sbin/ifconfig/ifconfig.c
==============================================================================
--- head/sbin/ifconfig/ifconfig.c	Mon Aug 26 21:00:14 2019	(r351521)
+++ head/sbin/ifconfig/ifconfig.c	Tue Aug 27 00:01:56 2019	(r351522)
@@ -1257,7 +1257,7 @@ unsetifdescr(const char *val, int value, int s, const 
 "\020\1RXCSUM\2TXCSUM\3NETCONS\4VLAN_MTU\5VLAN_HWTAGGING\6JUMBO_MTU\7POLLING" \
 "\10VLAN_HWCSUM\11TSO4\12TSO6\13LRO\14WOL_UCAST\15WOL_MCAST\16WOL_MAGIC" \
 "\17TOE4\20TOE6\21VLAN_HWFILTER\23VLAN_HWTSO\24LINKSTATE\25NETMAP" \
-"\26RXCSUM_IPV6\27TXCSUM_IPV6\31TXRTLMT\32HWRXTSTMP\33NOMAP"
+"\26RXCSUM_IPV6\27TXCSUM_IPV6\31TXRTLMT\32HWRXTSTMP\33NOMAP\34TXTLS4\35TXTLS6"
 
 /*
  * Print the status of the interface.  If an address family was
@@ -1585,6 +1585,8 @@ static struct cmd basic_cmds[] = {
 	DEF_CMD("-toe",		-IFCAP_TOE,	setifcap),
 	DEF_CMD("lro",		IFCAP_LRO,	setifcap),
 	DEF_CMD("-lro",		-IFCAP_LRO,	setifcap),
+	DEF_CMD("txtls",	IFCAP_TXTLS,	setifcap),
+	DEF_CMD("-txtls",	-IFCAP_TXTLS,	setifcap),
 	DEF_CMD("wol",		IFCAP_WOL,	setifcap),
 	DEF_CMD("-wol",		-IFCAP_WOL,	setifcap),
 	DEF_CMD("wol_ucast",	IFCAP_WOL_UCAST,	setifcap),

Modified: head/share/man/man4/tcp.4
==============================================================================
--- head/share/man/man4/tcp.4	Mon Aug 26 21:00:14 2019	(r351521)
+++ head/share/man/man4/tcp.4	Tue Aug 27 00:01:56 2019	(r351522)
@@ -34,7 +34,7 @@
 .\"     From: @(#)tcp.4	8.1 (Berkeley) 6/5/93
 .\" $FreeBSD$
 .\"
-.Dd July 23, 2019
+.Dd August 26, 2019
 .Dt TCP 4
 .Os
 .Sh NAME
@@ -293,6 +293,51 @@ If an SADB entry cannot be found for the destination,
 the system does not send any outgoing segments and drops any inbound segments.
 .Pp
 Each dropped segment is taken into account in the TCP protocol statistics.
+.It Dv TCP_TXTLS_ENABLE
+Enable in-kernel Transport Layer Security (TLS) for data written to this
+socket.
+The
+.Vt struct tls_so_enable
+argument defines the encryption and authentication algorithms and keys
+used to encrypt the socket data as well as the maximum TLS record
+payload size.
+.Pp
+All data written to this socket will be encapsulated in TLS records
+and subsequently encrypted.
+By default all data written to this socket is treated as application data.
+Individual TLS records with a type other than application data
+(for example, handshake messages),
+may be transmitted by invoking
+.Xr sendmsg 2
+with a custom TLS record type set in a
+.Dv TLS_SET_RECORD_TYPE
+control message.
+The payload of this control message is a single byte holding the desired
+TLS record type.
+.Pp
+Data read from this socket will still be encrypted and must be parsed by
+a TLS-aware consumer.
+.Pp
+At present, only a single key may be set on a socket.
+As such, users of this option must disable rekeying.
+.It Dv TCP_TXTLS_MODE
+The integer argument can be used to get or set the current TLS mode of a
+socket.
+Setting the mode can only used to toggle between software and NIC TLS after
+TLS has been initially enabled via the
+.Dv TCP_TXTLS_ENABLE
+option.
+The available modes are:
+.Bl -tag -width "Dv TCP_TLS_MODE_IFNET"
+.It Dv TCP_TLS_MODE_NONE
+In-kernel TLS framing and encryption is not enabled for this socket.
+.It Dv TCP_TLS_MODE_SW
+TLS records are encrypted by the kernel prior to placing the data in the
+socket buffer.
+Typically this encryption is performed in software.
+.It Dv TCP_TLS_MODE_IFNET
+TLS records are encrypted by the network interface card (NIC).
+.El
 .El
 .Pp
 The option level for the

Modified: head/sys/conf/NOTES
==============================================================================
--- head/sys/conf/NOTES	Mon Aug 26 21:00:14 2019	(r351521)
+++ head/sys/conf/NOTES	Tue Aug 27 00:01:56 2019	(r351522)
@@ -654,6 +654,10 @@ options 	IPSEC			#IP security (requires device crypto)
 options		IPSEC_SUPPORT
 #options 	IPSEC_DEBUG		#debug for IP security
 
+
+# TLS framing and encryption of data transmitted over TCP sockets.
+options		KERN_TLS		# TLS transmit offload
+
 #
 # SMB/CIFS requester
 # NETSMB enables support for SMB protocol, it requires LIBMCHAIN and LIBICONV

Modified: head/sys/conf/files
==============================================================================
--- head/sys/conf/files	Mon Aug 26 21:00:14 2019	(r351521)
+++ head/sys/conf/files	Tue Aug 27 00:01:56 2019	(r351522)
@@ -3862,6 +3862,7 @@ kern/tty_ttydisc.c		standard
 kern/uipc_accf.c		standard
 kern/uipc_debug.c		optional ddb
 kern/uipc_domain.c		standard
+kern/uipc_ktls.c		optional kern_tls
 kern/uipc_mbuf.c		standard
 kern/uipc_mbuf2.c		standard
 kern/uipc_mbufhash.c		standard

Modified: head/sys/conf/options
==============================================================================
--- head/sys/conf/options	Mon Aug 26 21:00:14 2019	(r351521)
+++ head/sys/conf/options	Tue Aug 27 00:01:56 2019	(r351522)
@@ -435,6 +435,7 @@ IPSEC			opt_ipsec.h
 IPSEC_DEBUG		opt_ipsec.h
 IPSEC_SUPPORT		opt_ipsec.h
 IPSTEALTH
+KERN_TLS
 KRPC
 LIBALIAS
 LIBMCHAIN

Modified: head/sys/kern/kern_mbuf.c
==============================================================================
--- head/sys/kern/kern_mbuf.c	Mon Aug 26 21:00:14 2019	(r351521)
+++ head/sys/kern/kern_mbuf.c	Tue Aug 27 00:01:56 2019	(r351522)
@@ -31,6 +31,7 @@
 __FBSDID("$FreeBSD$");
 
 #include "opt_param.h"
+#include "opt_kern_tls.h"
 
 #include <sys/param.h>
 #include <sys/conf.h>
@@ -41,10 +42,12 @@ __FBSDID("$FreeBSD$");
 #include <sys/domain.h>
 #include <sys/eventhandler.h>
 #include <sys/kernel.h>
+#include <sys/ktls.h>
 #include <sys/limits.h>
 #include <sys/lock.h>
 #include <sys/mutex.h>
 #include <sys/protosw.h>
+#include <sys/refcount.h>
 #include <sys/sf_buf.h>
 #include <sys/smp.h>
 #include <sys/socket.h>
@@ -112,10 +115,10 @@ int nmbjumbop;			/* limits number of page size jumbo c
 int nmbjumbo9;			/* limits number of 9k jumbo clusters */
 int nmbjumbo16;			/* limits number of 16k jumbo clusters */
 
-bool mb_use_ext_pgs;		/* use EXT_PGS mbufs for sendfile */
+bool mb_use_ext_pgs;		/* use EXT_PGS mbufs for sendfile & TLS */
 SYSCTL_BOOL(_kern_ipc, OID_AUTO, mb_use_ext_pgs, CTLFLAG_RWTUN,
     &mb_use_ext_pgs, 0,
-    "Use unmapped mbufs for sendfile(2)");
+    "Use unmapped mbufs for sendfile(2) and TLS offload");
 
 static quad_t maxmbufmem;	/* overall real memory limit for all mbufs */
 
@@ -1281,13 +1284,27 @@ mb_free_ext(struct mbuf *m)
 			uma_zfree(zone_jumbo16, m->m_ext.ext_buf);
 			uma_zfree(zone_mbuf, mref);
 			break;
-		case EXT_PGS:
+		case EXT_PGS: {
+#ifdef KERN_TLS
+			struct mbuf_ext_pgs *pgs;
+			struct ktls_session *tls;
+#endif
+
 			KASSERT(mref->m_ext.ext_free != NULL,
 			    ("%s: ext_free not set", __func__));
 			mref->m_ext.ext_free(mref);
-			uma_zfree(zone_extpgs, mref->m_ext.ext_pgs);
+#ifdef KERN_TLS
+			pgs = mref->m_ext.ext_pgs;
+			tls = pgs->tls;
+			if (tls != NULL &&
+			    !refcount_release_if_not_last(&tls->refcount))
+				ktls_enqueue_to_free(pgs);
+			else
+#endif
+				uma_zfree(zone_extpgs, mref->m_ext.ext_pgs);
 			uma_zfree(zone_mbuf, mref);
 			break;
+		}
 		case EXT_SFBUF:
 		case EXT_NET_DRV:
 		case EXT_MOD_TYPE:

Modified: head/sys/kern/kern_sendfile.c
==============================================================================
--- head/sys/kern/kern_sendfile.c	Mon Aug 26 21:00:14 2019	(r351521)
+++ head/sys/kern/kern_sendfile.c	Tue Aug 27 00:01:56 2019	(r351522)
@@ -30,12 +30,15 @@
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD$");
 
+#include "opt_kern_tls.h"
+
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/capsicum.h>
 #include <sys/kernel.h>
 #include <netinet/in.h>
 #include <sys/lock.h>
+#include <sys/ktls.h>
 #include <sys/mutex.h>
 #include <sys/sysproto.h>
 #include <sys/malloc.h>
@@ -85,6 +88,7 @@ struct sf_io {
 	int		npages;
 	struct socket	*so;
 	struct mbuf	*m;
+	struct ktls_session *tls;
 	vm_page_t	pa[];
 };
 
@@ -262,6 +266,15 @@ sendfile_iodone(void *arg, vm_page_t *pg, int count, i
 	if (!refcount_release(&sfio->nios))
 		return;
 
+#ifdef INVARIANTS
+	if ((sfio->m->m_flags & M_EXT) != 0 &&
+	    sfio->m->m_ext.ext_type == EXT_PGS)
+		KASSERT(sfio->tls == sfio->m->m_ext.ext_pgs->tls,
+		    ("TLS session mismatch"));
+	else
+		KASSERT(sfio->tls == NULL,
+		    ("non-ext_pgs mbuf with TLS session"));
+#endif
 	CURVNET_SET(so->so_vnet);
 	if (sfio->error) {
 		/*
@@ -279,12 +292,29 @@ sendfile_iodone(void *arg, vm_page_t *pg, int count, i
 		so->so_error = EIO;
 
 		mb_free_notready(sfio->m, sfio->npages);
+#ifdef KERN_TLS
+	} else if (sfio->tls != NULL && sfio->tls->sw_encrypt != NULL) {
+		/*
+		 * I/O operation is complete, but we still need to
+		 * encrypt.  We cannot do this in the interrupt thread
+		 * of the disk controller, so forward the mbufs to a
+		 * different thread.
+		 *
+		 * Donate the socket reference from sfio to rather
+		 * than explicitly invoking soref().
+		 */
+		ktls_enqueue(sfio->m, so, sfio->npages);
+		goto out_with_ref;
+#endif
 	} else
 		(void)(so->so_proto->pr_usrreqs->pru_ready)(so, sfio->m,
 		    sfio->npages);
 
 	SOCK_LOCK(so);
 	sorele(so);
+#ifdef KERN_TLS
+out_with_ref:
+#endif
 	CURVNET_RESTORE();
 	free(sfio, M_TEMP);
 }
@@ -526,6 +556,9 @@ vn_sendfile(struct file *fp, int sockfd, struct uio *h
 	struct vnode *vp;
 	struct vm_object *obj;
 	struct socket *so;
+#ifdef KERN_TLS
+	struct ktls_session *tls;
+#endif
 	struct mbuf_ext_pgs *ext_pgs;
 	struct mbuf *m, *mh, *mhtail;
 	struct sf_buf *sf;
@@ -534,12 +567,18 @@ vn_sendfile(struct file *fp, int sockfd, struct uio *h
 	struct vattr va;
 	off_t off, sbytes, rem, obj_size;
 	int bsize, error, ext_pgs_idx, hdrlen, max_pgs, softerr;
+#ifdef KERN_TLS
+	int tls_enq_cnt;
+#endif
 	bool use_ext_pgs;
 
 	obj = NULL;
 	so = NULL;
 	m = mh = NULL;
 	sfs = NULL;
+#ifdef KERN_TLS
+	tls = NULL;
+#endif
 	hdrlen = sbytes = 0;
 	softerr = 0;
 	use_ext_pgs = false;
@@ -576,6 +615,9 @@ vn_sendfile(struct file *fp, int sockfd, struct uio *h
 	 * we implement that, but possibly shouldn't.
 	 */
 	(void)sblock(&so->so_snd, SBL_WAIT | SBL_NOINTR);
+#ifdef KERN_TLS
+	tls = ktls_hold(so->so_snd.sb_tls_info);
+#endif
 
 	/*
 	 * Loop through the pages of the file, starting with the requested
@@ -669,7 +711,14 @@ retry_space:
 		if (hdr_uio != NULL && hdr_uio->uio_resid > 0) {
 			hdr_uio->uio_td = td;
 			hdr_uio->uio_rw = UIO_WRITE;
-			mh = m_uiotombuf(hdr_uio, M_WAITOK, space, 0, 0);
+#ifdef KERN_TLS
+			if (tls != NULL)
+				mh = m_uiotombuf(hdr_uio, M_WAITOK, space,
+				    tls->params.max_frame_len, M_NOMAP);
+			else
+#endif
+				mh = m_uiotombuf(hdr_uio, M_WAITOK,
+				    space, 0, 0);
 			hdrlen = m_length(mh, &mhtail);
 			space -= hdrlen;
 			/*
@@ -743,6 +792,15 @@ retry_space:
 		sfio->so = so;
 		sfio->error = 0;
 
+#ifdef KERN_TLS
+		/*
+		 * This doesn't use ktls_hold() because sfio->m will
+		 * also have a reference on 'tls' that will be valid
+		 * for all of sfio's lifetime.
+		 */
+		sfio->tls = tls;
+#endif
+
 		error = sendfile_swapin(obj, sfio, &nios, off, space, npages,
 		    rhpages, flags);
 		if (error != 0) {
@@ -763,11 +821,22 @@ retry_space:
 		 * bufs are restricted to TCP as that is what has been
 		 * tested.  In particular, unmapped mbufs have not
 		 * been tested with UNIX-domain sockets.
+		 *
+		 * TLS frames always require unmapped mbufs.
 		 */
-		if (mb_use_ext_pgs &&
-		    so->so_proto->pr_protocol == IPPROTO_TCP) {
+		if ((mb_use_ext_pgs &&
+		    so->so_proto->pr_protocol == IPPROTO_TCP)
+#ifdef KERN_TLS
+		    || tls != NULL
+#endif
+		    ) {
 			use_ext_pgs = true;
-			max_pgs = MBUF_PEXT_MAX_PGS;
+#ifdef KERN_TLS
+			if (tls != NULL)
+				max_pgs = num_pages(tls->params.max_frame_len);
+			else
+#endif
+				max_pgs = MBUF_PEXT_MAX_PGS;
 
 			/* Start at last index, to wrap on first use. */
 			ext_pgs_idx = max_pgs - 1;
@@ -946,6 +1015,14 @@ prepend_header:
 		    __func__, m_length(m, NULL), space, hdrlen));
 
 		CURVNET_SET(so->so_vnet);
+#ifdef KERN_TLS
+		if (tls != NULL) {
+			error = ktls_frame(m, tls, &tls_enq_cnt,
+			    TLS_RLTYPE_APP);
+			if (error != 0)
+				goto done;
+		}
+#endif
 		if (nios == 0) {
 			/*
 			 * If sendfile_swapin() didn't initiate any I/Os,
@@ -954,8 +1031,16 @@ prepend_header:
 			 * PRUS_NOTREADY flag.
 			 */
 			free(sfio, M_TEMP);
-			error = (*so->so_proto->pr_usrreqs->pru_send)
-			    (so, 0, m, NULL, NULL, td);
+#ifdef KERN_TLS
+			if (tls != NULL && tls->sw_encrypt != NULL) {
+				error = (*so->so_proto->pr_usrreqs->pru_send)
+				    (so, PRUS_NOTREADY, m, NULL, NULL, td);
+				soref(so);
+				ktls_enqueue(m, so, tls_enq_cnt);
+			} else
+#endif
+				error = (*so->so_proto->pr_usrreqs->pru_send)
+				    (so, 0, m, NULL, NULL, td);
 		} else {
 			sfio->npages = npages;
 			soref(so);
@@ -1019,6 +1104,10 @@ out:
 		mtx_destroy(&sfs->mtx);
 		free(sfs, M_TEMP);
 	}
+#ifdef KERN_TLS
+	if (tls != NULL)
+		ktls_free(tls);
+#endif
 
 	if (error == ERESTART)
 		error = EINTR;

Added: head/sys/kern/uipc_ktls.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/kern/uipc_ktls.c	Tue Aug 27 00:01:56 2019	(r351522)
@@ -0,0 +1,1450 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2014-2019 Netflix Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "opt_inet.h"
+#include "opt_inet6.h"
+#include "opt_rss.h"
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/ktls.h>
+#include <sys/lock.h>
+#include <sys/mbuf.h>
+#include <sys/mutex.h>
+#include <sys/rmlock.h>
+#include <sys/proc.h>
+#include <sys/protosw.h>
+#include <sys/refcount.h>
+#include <sys/smp.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/sysctl.h>
+#include <sys/taskqueue.h>
+#include <sys/kthread.h>
+#include <sys/uio.h>
+#include <sys/vmmeter.h>
+#if defined(__aarch64__) || defined(__amd64__) || defined(__i386__)
+#include <machine/pcb.h>
+#endif
+#include <machine/vmparam.h>
+#ifdef RSS
+#include <net/netisr.h>
+#include <net/rss_config.h>
+#endif
+#if defined(INET) || defined(INET6)
+#include <netinet/in.h>
+#include <netinet/in_pcb.h>
+#endif
+#include <netinet/tcp_var.h>
+#include <opencrypto/xform.h>
+#include <vm/uma_dbg.h>
+#include <vm/vm.h>
+#include <vm/vm_pageout.h>
+#include <vm/vm_page.h>
+
+struct ktls_wq {
+	struct mtx	mtx;
+	STAILQ_HEAD(, mbuf_ext_pgs) head;
+	bool		running;
+} __aligned(CACHE_LINE_SIZE);
+
+static struct ktls_wq *ktls_wq;
+static struct proc *ktls_proc;
+LIST_HEAD(, ktls_crypto_backend) ktls_backends;
+static struct rmlock ktls_backends_lock;
+static uma_zone_t ktls_session_zone;
+static uint16_t ktls_cpuid_lookup[MAXCPU];
+
+SYSCTL_NODE(_kern_ipc, OID_AUTO, tls, CTLFLAG_RW, 0,
+    "Kernel TLS offload");
+SYSCTL_NODE(_kern_ipc_tls, OID_AUTO, stats, CTLFLAG_RW, 0,
+    "Kernel TLS offload stats");
+
+static int ktls_allow_unload;
+SYSCTL_INT(_kern_ipc_tls, OID_AUTO, allow_unload, CTLFLAG_RDTUN,
+    &ktls_allow_unload, 0, "Allow software crypto modules to unload");
+
+#ifdef RSS
+static int ktls_bind_threads = 1;
+#else
+static int ktls_bind_threads;
+#endif
+SYSCTL_INT(_kern_ipc_tls, OID_AUTO, bind_threads, CTLFLAG_RDTUN,
+    &ktls_bind_threads, 0,
+    "Bind crypto threads to cores or domains at boot");
+
+static u_int ktls_maxlen = 16384;
+SYSCTL_UINT(_kern_ipc_tls, OID_AUTO, maxlen, CTLFLAG_RWTUN,
+    &ktls_maxlen, 0, "Maximum TLS record size");
+
+static int ktls_number_threads;
+SYSCTL_INT(_kern_ipc_tls_stats, OID_AUTO, threads, CTLFLAG_RD,
+    &ktls_number_threads, 0,
+    "Number of TLS threads in thread-pool");
+
+static bool ktls_offload_enable;
+SYSCTL_BOOL(_kern_ipc_tls, OID_AUTO, enable, CTLFLAG_RW,
+    &ktls_offload_enable, 0,
+    "Enable support for kernel TLS offload");
+
+static bool ktls_cbc_enable = true;
+SYSCTL_BOOL(_kern_ipc_tls, OID_AUTO, cbc_enable, CTLFLAG_RW,
+    &ktls_cbc_enable, 1,
+    "Enable Support of AES-CBC crypto for kernel TLS");
+
+static counter_u64_t ktls_tasks_active;
+SYSCTL_COUNTER_U64(_kern_ipc_tls, OID_AUTO, tasks_active, CTLFLAG_RD,
+    &ktls_tasks_active, "Number of active tasks");
+
+static counter_u64_t ktls_cnt_on;
+SYSCTL_COUNTER_U64(_kern_ipc_tls_stats, OID_AUTO, so_inqueue, CTLFLAG_RD,
+    &ktls_cnt_on, "Number of TLS records in queue to tasks for SW crypto");
+
+static counter_u64_t ktls_offload_total;
+SYSCTL_COUNTER_U64(_kern_ipc_tls_stats, OID_AUTO, offload_total,
+    CTLFLAG_RD, &ktls_offload_total,
+    "Total successful TLS setups (parameters set)");
+
+static counter_u64_t ktls_offload_enable_calls;
+SYSCTL_COUNTER_U64(_kern_ipc_tls_stats, OID_AUTO, enable_calls,
+    CTLFLAG_RD, &ktls_offload_enable_calls,
+    "Total number of TLS enable calls made");
+
+static counter_u64_t ktls_offload_active;
+SYSCTL_COUNTER_U64(_kern_ipc_tls_stats, OID_AUTO, active, CTLFLAG_RD,
+    &ktls_offload_active, "Total Active TLS sessions");
+
+static counter_u64_t ktls_offload_failed_crypto;
+SYSCTL_COUNTER_U64(_kern_ipc_tls_stats, OID_AUTO, failed_crypto, CTLFLAG_RD,
+    &ktls_offload_failed_crypto, "Total TLS crypto failures");
+
+static counter_u64_t ktls_switch_to_ifnet;
+SYSCTL_COUNTER_U64(_kern_ipc_tls_stats, OID_AUTO, switch_to_ifnet, CTLFLAG_RD,
+    &ktls_switch_to_ifnet, "TLS sessions switched from SW to ifnet");
+
+static counter_u64_t ktls_switch_to_sw;
+SYSCTL_COUNTER_U64(_kern_ipc_tls_stats, OID_AUTO, switch_to_sw, CTLFLAG_RD,
+    &ktls_switch_to_sw, "TLS sessions switched from ifnet to SW");
+
+static counter_u64_t ktls_switch_failed;
+SYSCTL_COUNTER_U64(_kern_ipc_tls_stats, OID_AUTO, switch_failed, CTLFLAG_RD,
+    &ktls_switch_failed, "TLS sessions unable to switch between SW and ifnet");
+
+SYSCTL_NODE(_kern_ipc_tls, OID_AUTO, sw, CTLFLAG_RD, 0,
+    "Software TLS session stats");
+SYSCTL_NODE(_kern_ipc_tls, OID_AUTO, ifnet, CTLFLAG_RD, 0,
+    "Hardware (ifnet) TLS session stats");
+
+static counter_u64_t ktls_sw_cbc;
+SYSCTL_COUNTER_U64(_kern_ipc_tls_sw, OID_AUTO, cbc, CTLFLAG_RD, &ktls_sw_cbc,
+    "Active number of software TLS sessions using AES-CBC");
+
+static counter_u64_t ktls_sw_gcm;
+SYSCTL_COUNTER_U64(_kern_ipc_tls_sw, OID_AUTO, gcm, CTLFLAG_RD, &ktls_sw_gcm,
+    "Active number of software TLS sessions using AES-GCM");
+
+static counter_u64_t ktls_ifnet_cbc;
+SYSCTL_COUNTER_U64(_kern_ipc_tls_ifnet, OID_AUTO, cbc, CTLFLAG_RD,
+    &ktls_ifnet_cbc,
+    "Active number of ifnet TLS sessions using AES-CBC");
+
+static counter_u64_t ktls_ifnet_gcm;
+SYSCTL_COUNTER_U64(_kern_ipc_tls_ifnet, OID_AUTO, gcm, CTLFLAG_RD,
+    &ktls_ifnet_gcm,
+    "Active number of ifnet TLS sessions using AES-GCM");
+
+static counter_u64_t ktls_ifnet_reset;
+SYSCTL_COUNTER_U64(_kern_ipc_tls_ifnet, OID_AUTO, reset, CTLFLAG_RD,
+    &ktls_ifnet_reset, "TLS sessions updated to a new ifnet send tag");
+
+static counter_u64_t ktls_ifnet_reset_dropped;
+SYSCTL_COUNTER_U64(_kern_ipc_tls_ifnet, OID_AUTO, reset_dropped, CTLFLAG_RD,
+    &ktls_ifnet_reset_dropped,
+    "TLS sessions dropped after failing to update ifnet send tag");
+
+static counter_u64_t ktls_ifnet_reset_failed;
+SYSCTL_COUNTER_U64(_kern_ipc_tls_ifnet, OID_AUTO, reset_failed, CTLFLAG_RD,
+    &ktls_ifnet_reset_failed,
+    "TLS sessions that failed to allocate a new ifnet send tag");
+
+static int ktls_ifnet_permitted;
+SYSCTL_UINT(_kern_ipc_tls_ifnet, OID_AUTO, permitted, CTLFLAG_RWTUN,
+    &ktls_ifnet_permitted, 1,
+    "Whether to permit hardware (ifnet) TLS sessions");
+
+static MALLOC_DEFINE(M_KTLS, "ktls", "Kernel TLS");
+
+static void ktls_cleanup(struct ktls_session *tls);
+#if defined(INET) || defined(INET6)
+static void ktls_reset_send_tag(void *context, int pending);
+#endif
+static void ktls_work_thread(void *ctx);
+
+int
+ktls_crypto_backend_register(struct ktls_crypto_backend *be)
+{
+	struct ktls_crypto_backend *curr_be, *tmp;
+
+	if (be->api_version != KTLS_API_VERSION) {
+		printf("KTLS: API version mismatch (%d vs %d) for %s\n",
+		    be->api_version, KTLS_API_VERSION,
+		    be->name);
+		return (EINVAL);
+	}
+
+	rm_wlock(&ktls_backends_lock);
+	printf("KTLS: Registering crypto method %s with prio %d\n",
+	       be->name, be->prio);
+	if (LIST_EMPTY(&ktls_backends)) {
+		LIST_INSERT_HEAD(&ktls_backends, be, next);
+	} else {
+		LIST_FOREACH_SAFE(curr_be, &ktls_backends, next, tmp) {
+			if (curr_be->prio < be->prio) {
+				LIST_INSERT_BEFORE(curr_be, be, next);
+				break;
+			}
+			if (LIST_NEXT(curr_be, next) == NULL) {
+				LIST_INSERT_AFTER(curr_be, be, next);
+				break;
+			}
+		}
+	}
+	rm_wunlock(&ktls_backends_lock);
+	return (0);
+}
+
+int
+ktls_crypto_backend_deregister(struct ktls_crypto_backend *be)
+{
+	struct ktls_crypto_backend *tmp;
+
+	/*
+	 * Don't error if the backend isn't registered.  This permits
+	 * MOD_UNLOAD handlers to use this function unconditionally.
+	 */
+	rm_wlock(&ktls_backends_lock);
+	LIST_FOREACH(tmp, &ktls_backends, next) {
+		if (tmp == be)
+			break;
+	}
+	if (tmp == NULL) {
+		rm_wunlock(&ktls_backends_lock);
+		return (0);
+	}
+
+	if (!ktls_allow_unload) {
+		rm_wunlock(&ktls_backends_lock);
+		printf(
+		    "KTLS: Deregistering crypto method %s is not supported\n",
+		    be->name);
+		return (EBUSY);
+	}
+
+	if (be->use_count) {
+		rm_wunlock(&ktls_backends_lock);
+		return (EBUSY);
+	}
+
+	LIST_REMOVE(be, next);
+	rm_wunlock(&ktls_backends_lock);
+	return (0);
+}
+
+#if defined(INET) || defined(INET6)
+static uint16_t
+ktls_get_cpu(struct socket *so)
+{
+	struct inpcb *inp;
+	uint16_t cpuid;
+
+	inp = sotoinpcb(so);
+#ifdef RSS
+	cpuid = rss_hash2cpuid(inp->inp_flowid, inp->inp_flowtype);
+	if (cpuid != NETISR_CPUID_NONE)
+		return (cpuid);
+#endif
+	/*
+	 * Just use the flowid to shard connections in a repeatable
+	 * fashion.  Note that some crypto backends rely on the
+	 * serialization provided by having the same connection use
+	 * the same queue.
+	 */
+	cpuid = ktls_cpuid_lookup[inp->inp_flowid % ktls_number_threads];
+	return (cpuid);
+}
+#endif
+
+static void
+ktls_init(void *dummy __unused)
+{
+	struct thread *td;
+	struct pcpu *pc;
+	cpuset_t mask;
+	int error, i;
+
+	ktls_tasks_active = counter_u64_alloc(M_WAITOK);
+	ktls_cnt_on = counter_u64_alloc(M_WAITOK);
+	ktls_offload_total = counter_u64_alloc(M_WAITOK);
+	ktls_offload_enable_calls = counter_u64_alloc(M_WAITOK);
+	ktls_offload_active = counter_u64_alloc(M_WAITOK);
+	ktls_offload_failed_crypto = counter_u64_alloc(M_WAITOK);
+	ktls_switch_to_ifnet = counter_u64_alloc(M_WAITOK);
+	ktls_switch_to_sw = counter_u64_alloc(M_WAITOK);
+	ktls_switch_failed = counter_u64_alloc(M_WAITOK);
+	ktls_sw_cbc = counter_u64_alloc(M_WAITOK);
+	ktls_sw_gcm = counter_u64_alloc(M_WAITOK);
+	ktls_ifnet_cbc = counter_u64_alloc(M_WAITOK);
+	ktls_ifnet_gcm = counter_u64_alloc(M_WAITOK);
+	ktls_ifnet_reset = counter_u64_alloc(M_WAITOK);
+	ktls_ifnet_reset_dropped = counter_u64_alloc(M_WAITOK);
+	ktls_ifnet_reset_failed = counter_u64_alloc(M_WAITOK);
+
+	rm_init(&ktls_backends_lock, "ktls backends");
+	LIST_INIT(&ktls_backends);
+
+	ktls_wq = malloc(sizeof(*ktls_wq) * (mp_maxid + 1), M_KTLS,
+	    M_WAITOK | M_ZERO);
+
+	ktls_session_zone = uma_zcreate("ktls_session",
+	    sizeof(struct ktls_session),
+#ifdef INVARIANTS
+	    trash_ctor, trash_dtor, trash_init, trash_fini,
+#else
+	    NULL, NULL, NULL, NULL,
+#endif
+	    UMA_ALIGN_CACHE, 0);
+
+	/*
+	 * Initialize the workqueues to run the TLS work.  We create a
+	 * work queue for each CPU.
+	 */
+	CPU_FOREACH(i) {
+		STAILQ_INIT(&ktls_wq[i].head);
+		mtx_init(&ktls_wq[i].mtx, "ktls work queue", NULL, MTX_DEF);
+		error = kproc_kthread_add(ktls_work_thread, &ktls_wq[i],
+		    &ktls_proc, &td, 0, 0, "KTLS", "ktls_thr_%d", i);
+		if (error)
+			panic("Can't add KTLS thread %d error %d", i, error);
+
+		/*
+		 * Bind threads to cores.  If ktls_bind_threads is >
+		 * 1, then we bind to the NUMA domain.
+		 */
+		if (ktls_bind_threads) {
+			if (ktls_bind_threads > 1) {
+				pc = pcpu_find(i);
+				CPU_COPY(&cpuset_domain[pc->pc_domain], &mask);
+			} else {
+				CPU_SETOF(i, &mask);
+			}
+			error = cpuset_setthread(td->td_tid, &mask);
+			if (error)
+				panic(
+			    "Unable to bind KTLS thread for CPU %d error %d",
+				     i, error);
+		}
+		ktls_cpuid_lookup[ktls_number_threads] = i;
+		ktls_number_threads++;
+	}
+	printf("KTLS: Initialized %d threads\n", ktls_number_threads);
+}
+SYSINIT(ktls, SI_SUB_SMP + 1, SI_ORDER_ANY, ktls_init, NULL);
+
+#if defined(INET) || defined(INET6)
+static int
+ktls_create_session(struct socket *so, struct tls_enable *en,
+    struct ktls_session **tlsp)
+{
+	struct ktls_session *tls;
+	int error;
+
+	/* Only TLS 1.0 - 1.2 are supported. */
+	if (en->tls_vmajor != TLS_MAJOR_VER_ONE)
+		return (EINVAL);
+	if (en->tls_vminor < TLS_MINOR_VER_ZERO ||
+	    en->tls_vminor > TLS_MINOR_VER_TWO)
+		return (EINVAL);
+
+	if (en->auth_key_len < 0 || en->auth_key_len > TLS_MAX_PARAM_SIZE)
+		return (EINVAL);
+	if (en->cipher_key_len < 0 || en->cipher_key_len > TLS_MAX_PARAM_SIZE)
+		return (EINVAL);
+	if (en->iv_len < 0 || en->iv_len > TLS_MAX_PARAM_SIZE)
+		return (EINVAL);
+
+	/* All supported algorithms require a cipher key. */
+	if (en->cipher_key_len == 0)
+		return (EINVAL);
+
+	/* No flags are currently supported. */
+	if (en->flags != 0)
+		return (EINVAL);
+
+	/* Common checks for supported algorithms. */
+	switch (en->cipher_algorithm) {
+	case CRYPTO_AES_NIST_GCM_16:
+		/*
+		 * auth_algorithm isn't used, but permit GMAC values
+		 * for compatibility.
+		 */
+		switch (en->auth_algorithm) {
+		case 0:
+		case CRYPTO_AES_128_NIST_GMAC:
+		case CRYPTO_AES_192_NIST_GMAC:
+		case CRYPTO_AES_256_NIST_GMAC:
+			break;
+		default:
+			return (EINVAL);
+		}
+		if (en->auth_key_len != 0)
+			return (EINVAL);
+		if (en->iv_len != TLS_AEAD_GCM_LEN)
+			return (EINVAL);
+		break;
+	case CRYPTO_AES_CBC:
+		switch (en->auth_algorithm) {
+		case CRYPTO_SHA1_HMAC:
+			/*
+			 * TLS 1.0 requires an implicit IV.  TLS 1.1+
+			 * all use explicit IVs.
+			 */
+			if (en->tls_vminor == TLS_MINOR_VER_ZERO) {
+				if (en->iv_len != TLS_CBC_IMPLICIT_IV_LEN)
+					return (EINVAL);
+				break;
+			}
+
+			/* FALLTHROUGH */
+		case CRYPTO_SHA2_256_HMAC:
+		case CRYPTO_SHA2_384_HMAC:
+			/* Ignore any supplied IV. */
+			en->iv_len = 0;
+			break;
+		default:
+			return (EINVAL);
+		}
+		if (en->auth_key_len == 0)
+			return (EINVAL);
+		break;
+	default:
+		return (EINVAL);
+	}
+
+	tls = uma_zalloc(ktls_session_zone, M_WAITOK | M_ZERO);
+
+	counter_u64_add(ktls_offload_active, 1);
+
+	refcount_init(&tls->refcount, 1);
+	TASK_INIT(&tls->reset_tag_task, 0, ktls_reset_send_tag, tls);
+
+	tls->wq_index = ktls_get_cpu(so);
+
+	tls->params.cipher_algorithm = en->cipher_algorithm;
+	tls->params.auth_algorithm = en->auth_algorithm;
+	tls->params.tls_vmajor = en->tls_vmajor;
+	tls->params.tls_vminor = en->tls_vminor;
+	tls->params.flags = en->flags;
+	tls->params.max_frame_len = min(TLS_MAX_MSG_SIZE_V10_2, ktls_maxlen);
+
+	/* Set the header and trailer lengths. */
+	tls->params.tls_hlen = sizeof(struct tls_record_layer);
+	switch (en->cipher_algorithm) {
+	case CRYPTO_AES_NIST_GCM_16:
+		tls->params.tls_hlen += 8;
+		tls->params.tls_tlen = AES_GMAC_HASH_LEN;
+		tls->params.tls_bs = 1;
+		break;
+	case CRYPTO_AES_CBC:
+		switch (en->auth_algorithm) {
+		case CRYPTO_SHA1_HMAC:
+			if (en->tls_vminor == TLS_MINOR_VER_ZERO) {
+				/* Implicit IV, no nonce. */
+			} else {
+				tls->params.tls_hlen += AES_BLOCK_LEN;
+			}
+			tls->params.tls_tlen = AES_BLOCK_LEN +
+			    SHA1_HASH_LEN;
+			break;
+		case CRYPTO_SHA2_256_HMAC:
+			tls->params.tls_hlen += AES_BLOCK_LEN;
+			tls->params.tls_tlen = AES_BLOCK_LEN +
+			    SHA2_256_HASH_LEN;
+			break;
+		case CRYPTO_SHA2_384_HMAC:
+			tls->params.tls_hlen += AES_BLOCK_LEN;
+			tls->params.tls_tlen = AES_BLOCK_LEN +
+			    SHA2_384_HASH_LEN;
+			break;
+		default:
+			panic("invalid hmac");
+		}
+		tls->params.tls_bs = AES_BLOCK_LEN;
+		break;
+	default:
+		panic("invalid cipher");
+	}
+
+	KASSERT(tls->params.tls_hlen <= MBUF_PEXT_HDR_LEN,
+	    ("TLS header length too long: %d", tls->params.tls_hlen));
+	KASSERT(tls->params.tls_tlen <= MBUF_PEXT_TRAIL_LEN,
+	    ("TLS trailer length too long: %d", tls->params.tls_tlen));
+
+	if (en->auth_key_len != 0) {
+		tls->params.auth_key_len = en->auth_key_len;
+		tls->params.auth_key = malloc(en->auth_key_len, M_KTLS,
+		    M_WAITOK);
+		error = copyin(en->auth_key, tls->params.auth_key,
+		    en->auth_key_len);
+		if (error)
+			goto out;
+	}
+
+	tls->params.cipher_key_len = en->cipher_key_len;
+	tls->params.cipher_key = malloc(en->cipher_key_len, M_KTLS, M_WAITOK);
+	error = copyin(en->cipher_key, tls->params.cipher_key,
+	    en->cipher_key_len);
+	if (error)
+		goto out;
+
+	/*
+	 * This holds the implicit portion of the nonce for GCM and
+	 * the initial implicit IV for TLS 1.0.  The explicit portions
+	 * of the IV are generated in ktls_frame() and ktls_seq().
+	 */
+	if (en->iv_len != 0) {
+		MPASS(en->iv_len <= sizeof(tls->params.iv));
+		tls->params.iv_len = en->iv_len;
+		error = copyin(en->iv, tls->params.iv, en->iv_len);
+		if (error)
+			goto out;
+	}
+
+	*tlsp = tls;
+	return (0);
+
+out:
+	ktls_cleanup(tls);
+	return (error);
+}
+
+static struct ktls_session *
+ktls_clone_session(struct ktls_session *tls)
+{
+	struct ktls_session *tls_new;
+

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201908270001.x7R01vUB052426>