path: root/sys/sys/sockbuf.h
diff options
authorJohn Baldwin <jhb@FreeBSD.org>2020-07-23 23:48:18 +0000
committerJohn Baldwin <jhb@FreeBSD.org>2020-07-23 23:48:18 +0000
commit3c0e5685051142f4125bf93d40a3e0b570e2327c (patch)
tree4515d83e0176f03e2cfdb90385a768306fd6f090 /sys/sys/sockbuf.h
parent3cee7cb26993aea9b089270f098a42ce0f4ba73b (diff)
Add support for KTLS RX via software decryption.
Allow TLS records to be decrypted in the kernel after being received by a NIC. At a high level this is somewhat similar to software KTLS for the transmit path except in reverse. Protocols enqueue mbufs containing encrypted TLS records (or portions of records) into the tail of a socket buffer and the KTLS layer decrypts those records before returning them to userland applications. However, there is an important difference: - In the transmit case, the socket buffer is always a single "record" holding a chain of mbufs. Not-yet-encrypted mbufs are marked not ready (M_NOTREADY) and released to protocols for transmit by marking mbufs ready once their data is encrypted. - In the receive case, incoming (encrypted) data appended to the socket buffer is still a single stream of data from the protocol, but decrypted TLS records are stored as separate records in the socket buffer and read individually via recvmsg(). Initially I tried to make this work by marking incoming mbufs as M_NOTREADY, but there didn't seemed to be a non-gross way to deal with picking a portion of the mbuf chain and turning it into a new record in the socket buffer after decrypting the TLS record it contained (along with prepending a control message). Also, such mbufs would also need to be "pinned" in some way while they are being decrypted such that a concurrent sbcut() wouldn't free them out from under the thread performing decryption. As such, I settled on the following solution: - Socket buffers now contain an additional chain of mbufs (sb_mtls, sb_mtlstail, and sb_tlscc) containing encrypted mbufs appended by the protocol layer. These mbufs are still marked M_NOTREADY, but soreceive*() generally don't know about them (except that they will block waiting for data to be decrypted for a blocking read). - Each time a new mbuf is appended to this TLS mbuf chain, the socket buffer peeks at the TLS record header at the head of the chain to determine the encrypted record's length. If enough data is queued for the TLS record, the socket is placed on a per-CPU TLS workqueue (reusing the existing KTLS workqueues and worker threads). - The worker thread loops over the TLS mbuf chain decrypting records until it runs out of data. Each record is detached from the TLS mbuf chain while it is being decrypted to keep the mbufs "pinned". However, a new sb_dtlscc field tracks the character count of the detached record and sbcut()/sbdrop() is updated to account for the detached record. After the record is decrypted, the worker thread first checks to see if sbcut() dropped the record. If so, it is freed (can happen when a socket is closed with pending data). Otherwise, the header and trailer are stripped from the original mbufs, a control message is created holding the decrypted TLS header, and the decrypted TLS record is appended to the "normal" socket buffer chain. (Side note: the SBCHECK() infrastucture was very useful as I was able to add assertions there about the TLS chain that caught several bugs during development.) Tested by: rmacklem (various versions) Relnotes: yes Sponsored by: Chelsio Communications Differential Revision: https://reviews.freebsd.org/D24628
Notes: svn path=/head/; revision=363464
Diffstat (limited to 'sys/sys/sockbuf.h')
1 files changed, 11 insertions, 0 deletions
diff --git a/sys/sys/sockbuf.h b/sys/sys/sockbuf.h
index 6e2340eabd50..4c56f4eaf234 100644
--- a/sys/sys/sockbuf.h
+++ b/sys/sys/sockbuf.h
@@ -38,6 +38,8 @@
* Constants for sb_flags field of struct sockbuf/xsockbuf.
+#define SB_TLS_RX 0x01 /* using KTLS on RX */
+#define SB_TLS_RX_RUNNING 0x02 /* KTLS RX operation running */
#define SB_WAIT 0x04 /* someone is waiting for data/space */
#define SB_SEL 0x08 /* someone is selecting */
#define SB_ASYNC 0x10 /* ASYNC I/O, need signals */
@@ -99,10 +101,14 @@ struct sockbuf {
u_int sb_ccnt; /* (a) number of clusters in buffer */
u_int sb_mbmax; /* (a) max chars of mbufs to use */
u_int sb_ctl; /* (a) non-data chars in buffer */
+ u_int sb_tlscc; /* (a) TLS chain characters */
+ u_int sb_tlsdcc; /* (a) TLS characters being decrypted */
int sb_lowat; /* (a) low water mark */
sbintime_t sb_timeo; /* (a) timeout for read/write */
uint64_t sb_tls_seqno; /* (a) TLS seqno */
struct ktls_session *sb_tls_info; /* (a + b) TLS state */
+ struct mbuf *sb_mtls; /* (a) TLS mbuf chain */
+ struct mbuf *sb_mtlstail; /* (a) last mbuf in TLS chain */
short sb_flags; /* (a) flags, see above */
int (*sb_upcall)(struct socket *, void *, int); /* (a) */
void *sb_upcallarg; /* (a) */
@@ -153,6 +159,9 @@ void sbappendrecord_locked(struct sockbuf *sb, struct mbuf *m0);
void sbcompress(struct sockbuf *sb, struct mbuf *m, struct mbuf *n);
struct mbuf *
sbcreatecontrol(caddr_t p, int size, int type, int level);
+struct mbuf *
+ sbcreatecontrol_how(void *p, int size, int type, int level,
+ int wait);
void sbdestroy(struct sockbuf *sb, struct socket *so);
void sbdrop(struct sockbuf *sb, int len);
void sbdrop_locked(struct sockbuf *sb, int len);
@@ -178,6 +187,8 @@ int sblock(struct sockbuf *sb, int flags);
void sbunlock(struct sockbuf *sb);
void sballoc(struct sockbuf *, struct mbuf *);
void sbfree(struct sockbuf *, struct mbuf *);
+void sballoc_ktls_rx(struct sockbuf *sb, struct mbuf *m);
+void sbfree_ktls_rx(struct sockbuf *sb, struct mbuf *m);
int sbready(struct sockbuf *, struct mbuf *, int);