You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficserver.apache.org by bn...@apache.org on 2023/10/18 22:35:33 UTC

[trafficserver] branch master updated: Move mgmt, iocore, proxy to src/ and include/ (#10638)

This is an automated email from the ASF dual-hosted git repository.

bneradt pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/trafficserver.git


The following commit(s) were added to refs/heads/master by this push:
     new 16cb2dd04f Move mgmt, iocore, proxy to src/ and include/ (#10638)
16cb2dd04f is described below

commit 16cb2dd04f8a4a0cb8f63223033ae72a135f6ca8
Author: Zhengxi Li <lz...@hotmail.com>
AuthorDate: Wed Oct 18 18:35:28 2023 -0400

    Move mgmt, iocore, proxy to src/ and include/ (#10638)
    
    This replaces PR #10558
    Some highlights:
    
    * The P_ files are left in src/
    * The I_ prefixes in public header files are removed
    
    Note: the include path cleanup would be left for another PR.
---
 .gitignore                                         |   93 +-
 CMakeLists.txt                                     |   11 +-
 ci/jenkins/bin/autest.sh                           |    2 +-
 contrib/python/compare_RecordsConfigcc.py          |    2 +-
 doc/Doxyfile                                       |    3 -
 include/api/InkAPIInternal.h                       |    8 +-
 include/iocore/aio/AIO.h                           |   85 +
 include/iocore/aio/AIO_fault_injection.h           |   72 +
 include/iocore/cache/Cache.h                       |  223 +
 include/iocore/cache/CacheDefs.h                   |  143 +
 include/iocore/cache/CacheEvacuateDocVC.h          |   72 +
 include/iocore/cache/CacheVC.h                     |  335 +
 .../iocore}/cache/HttpTransactCache.h              |    0
 .../I_Store.h => include/iocore/cache/Store.h      |    0
 include/iocore/dns/DNS.h                           |   36 +
 {iocore => include/iocore}/dns/DNSEventIO.h        |    0
 include/iocore/dns/DNSProcessor.h                  |  231 +
 {iocore => include/iocore}/dns/SRV.h               |    0
 include/iocore/dns/SplitDNS.h                      |   36 +
 .../iocore/dns/SplitDNSProcessor.h                 |    0
 include/iocore/eventsystem/Action.h                |  196 +
 include/iocore/eventsystem/ConfigProcessor.h       |  117 +
 include/iocore/eventsystem/Continuation.h          |  281 +
 include/iocore/eventsystem/EThread.h               |  644 ++
 include/iocore/eventsystem/Event.h                 |  292 +
 include/iocore/eventsystem/EventProcessor.h        |  402 +
 include/iocore/eventsystem/EventSystem.h           |   51 +
 .../iocore/eventsystem/IOBuffer.h                  |    0
 include/iocore/eventsystem/Lock.h                  |  681 ++
 include/iocore/eventsystem/MIOBufferWriter.h       |  189 +
 include/iocore/eventsystem/PriorityEventQueue.h    |  122 +
 .../iocore/eventsystem/Processor.h                 |    0
 include/iocore/eventsystem/ProtectedQueue.h        |   54 +
 .../iocore/eventsystem/ProxyAllocator.h            |    0
 include/iocore/eventsystem/RecProcess.h            |   40 +
 .../iocore/eventsystem/SocketManager.h             |    0
 include/iocore/eventsystem/Tasks.h                 |   38 +
 include/iocore/eventsystem/Thread.h                |  170 +
 include/iocore/eventsystem/VConnection.h           |  413 +
 include/iocore/eventsystem/VIO.h                   |  223 +
 include/iocore/hostdb/HostDB.h                     |   41 +
 include/iocore/hostdb/HostDBProcessor.h            |  887 ++
 include/iocore/hostdb/HostFile.h                   |   52 +
 .../iocore}/io_uring/IOUringEventIO.h              |    0
 .../iocore/io_uring/IO_URING.h                     |    0
 include/iocore/net/AcceptOptions.h                 |   90 +
 .../iocore}/net/AsyncSignalEventIO.h               |    0
 {iocore => include/iocore}/net/BIO_fastopen.h      |    0
 {iocore => include/iocore}/net/BoringSSLUtils.h    |    0
 {iocore => include/iocore}/net/EventIO.h           |    0
 include/iocore/net/Net.h                           |   91 +
 {iocore => include/iocore}/net/NetAcceptEventIO.h  |    0
 include/iocore/net/NetEvent.h                      |  141 +
 include/iocore/net/NetHandler.h                    |  236 +
 include/iocore/net/NetProcessor.h                  |  184 +
 include/iocore/net/NetTimeout.h                    |  263 +
 include/iocore/net/NetVCOptions.h                  |  318 +
 include/iocore/net/NetVConnection.h                |  703 ++
 include/iocore/net/PollCont.h                      |   43 +
 include/iocore/net/PreWarm.h                       |   50 +
 {iocore => include/iocore}/net/ProxyProtocol.h     |    0
 .../iocore}/net/QUICMultiCertConfigLoader.h        |    0
 {iocore => include/iocore}/net/QUICSupport.h       |    0
 {iocore => include/iocore}/net/ReadWriteEventIO.h  |    0
 .../iocore}/net/SNIActionPerformer.h               |    0
 {iocore => include/iocore}/net/SSLAPIHooks.h       |    0
 {iocore => include/iocore}/net/SSLDiags.h          |    0
 {iocore => include/iocore}/net/SSLDynlock.h        |    0
 {iocore => include/iocore}/net/SSLInternal.h       |    0
 {iocore => include/iocore}/net/SSLSNIConfig.h      |    0
 include/iocore/net/SSLSessionCache.h               |  218 +
 {iocore => include/iocore}/net/SSLSessionTicket.h  |    0
 include/iocore/net/SSLStats.h                      |  106 +
 {iocore => include/iocore}/net/SSLTypes.h          |    0
 include/iocore/net/SessionAccept.h                 |   79 +
 iocore/net/I_Socks.h => include/iocore/net/Socks.h |    0
 include/iocore/net/TLSALPNSupport.h                |  104 +
 {iocore => include/iocore}/net/TLSBasicSupport.h   |    0
 .../iocore}/net/TLSCertSwitchSupport.h             |    0
 .../iocore}/net/TLSEarlyDataSupport.h              |    0
 {iocore => include/iocore}/net/TLSSNISupport.h     |    0
 .../iocore}/net/TLSSessionResumptionSupport.h      |    0
 {iocore => include/iocore}/net/TLSTunnelSupport.h  |    0
 include/iocore/net/UDPConnection.h                 |  114 +
 {iocore => include/iocore}/net/UDPEventIO.h        |    0
 include/iocore/net/UDPNet.h                        |  111 +
 include/iocore/net/UDPPacket.h                     |  158 +
 {iocore => include/iocore}/net/YamlSNIConfig.h     |    0
 {iocore => include/iocore}/net/quic/MTHashTable.h  |    0
 {iocore => include/iocore}/net/quic/Mock.h         |    0
 .../iocore}/net/quic/QUICAckFrameCreator.h         |    0
 .../iocore}/net/quic/QUICAddrVerifyState.h         |    0
 .../iocore}/net/quic/QUICAltConnectionManager.h    |    0
 include/iocore/net/quic/QUICApplication.h          |   50 +
 .../iocore}/net/quic/QUICApplicationMap.h          |    0
 .../iocore}/net/quic/QUICBidirectionalStream.h     |    0
 {iocore => include/iocore}/net/quic/QUICConfig.h   |    0
 .../iocore}/net/quic/QUICCongestionController.h    |    0
 include/iocore/net/quic/QUICConnection.h           |   75 +
 .../iocore}/net/quic/QUICConnectionTable.h         |    0
 {iocore => include/iocore}/net/quic/QUICContext.h  |    0
 .../iocore}/net/quic/QUICCryptoStream.h            |    0
 .../iocore}/net/quic/QUICDebugNames.h              |    0
 {iocore => include/iocore}/net/quic/QUICEchoApp.h  |    0
 include/iocore/net/quic/QUICEvents.h               |   39 +
 include/iocore/net/quic/QUICFlowController.h       |  156 +
 include/iocore/net/quic/QUICFrame.h                |  911 ++
 .../iocore}/net/quic/QUICFrameDispatcher.h         |    0
 .../iocore}/net/quic/QUICFrameGenerator.h          |    0
 .../iocore}/net/quic/QUICFrameHandler.h            |    0
 .../iocore}/net/quic/QUICFrameRetransmitter.h      |    0
 {iocore => include/iocore}/net/quic/QUICGlobals.h  |    0
 {iocore => include/iocore}/net/quic/QUICHKDF.h     |    0
 .../iocore}/net/quic/QUICHandshake.h               |    0
 .../iocore}/net/quic/QUICHandshakeProtocol.h       |    0
 .../iocore}/net/quic/QUICIncomingFrameBuffer.h     |    0
 {iocore => include/iocore}/net/quic/QUICIntUtil.h  |    0
 .../iocore}/net/quic/QUICKeyGenerator.h            |    0
 include/iocore/net/quic/QUICLossDetector.h         |  183 +
 .../net/quic/QUICNewRenoCongestionController.h     |    0
 include/iocore/net/quic/QUICPacket.h               |  561 ++
 .../iocore}/net/quic/QUICPacketFactory.h           |    0
 .../iocore}/net/quic/QUICPacketHeaderProtector.h   |    0
 .../iocore/net/quic/QUICPacketPayloadProtector.h   |   53 +
 .../iocore}/net/quic/QUICPacketProtectionKeyInfo.h |    0
 include/iocore/net/quic/QUICPacketReceiveQueue.h   |   56 +
 include/iocore/net/quic/QUICPadder.h               |   57 +
 .../iocore}/net/quic/QUICPathManager.h             |    0
 .../iocore}/net/quic/QUICPathValidator.h           |    0
 include/iocore/net/quic/QUICPinger.h               |   52 +
 .../iocore}/net/quic/QUICResetTokenTable.h         |    0
 .../iocore}/net/quic/QUICRetryIntegrityTag.h       |    0
 {iocore => include/iocore}/net/quic/QUICStats.h    |    0
 include/iocore/net/quic/QUICStream.h               |  106 +
 .../iocore}/net/quic/QUICStreamAdapter.h           |    0
 .../iocore}/net/quic/QUICStreamFactory.h           |    0
 .../iocore}/net/quic/QUICStreamManager.h           |    0
 .../iocore}/net/quic/QUICStreamManager_native.h    |    0
 .../iocore}/net/quic/QUICStreamManager_quiche.h    |    0
 .../iocore}/net/quic/QUICStreamState.h             |    0
 include/iocore/net/quic/QUICStreamVCAdapter.h      |  106 +
 .../iocore}/net/quic/QUICStream_native.h           |    0
 .../iocore}/net/quic/QUICStream_quiche.h           |    0
 include/iocore/net/quic/QUICTLS.h                  |  128 +
 .../iocore}/net/quic/QUICTokenCreator.h            |    0
 .../net/quic/QUICTransferProgressProvider.h        |    0
 .../iocore}/net/quic/QUICTransportParameters.h     |    0
 include/iocore/net/quic/QUICTypes.h                |  673 ++
 .../iocore}/net/quic/QUICUnidirectionalStream.h    |    0
 .../iocore}/net/quic/QUICVersionNegotiator.h       |    0
 {iocore => include/iocore}/net/quic/qlog/QLog.h    |    0
 .../iocore}/net/quic/qlog/QLogEvent.h              |    0
 .../iocore}/net/quic/qlog/QLogFrame.h              |    0
 .../iocore}/net/quic/qlog/QLogListener.h           |    0
 .../iocore}/net/quic/qlog/QLogUtils.h              |    0
 .../I_Machine.h => include/iocore/utils/Machine.h  |    0
 include/iocore/utils/OneWayMultiTunnel.h           |  134 +
 include/iocore/utils/OneWayTunnel.h                |  211 +
 {iocore => include/iocore}/utils/diags.i           |    0
 {mgmt => include/mgmt}/config/FileManager.h        |    0
 {mgmt => include/mgmt}/rpc/config/JsonRPCConfig.h  |    0
 .../mgmt}/rpc/handlers/common/ErrorUtils.h         |    0
 include/mgmt/rpc/handlers/common/RecordsUtils.h    |  102 +
 {mgmt => include/mgmt}/rpc/handlers/common/Utils.h |    0
 include/mgmt/rpc/handlers/common/convert.h         |  179 +
 .../mgmt}/rpc/handlers/config/Configuration.h      |    0
 .../mgmt}/rpc/handlers/plugins/Plugins.h           |    0
 .../mgmt}/rpc/handlers/records/Records.h           |    0
 .../mgmt}/rpc/handlers/server/Server.h             |    0
 .../mgmt}/rpc/handlers/storage/Storage.h           |    0
 {mgmt => include/mgmt}/rpc/jsonrpc/Context.h       |    0
 {mgmt => include/mgmt}/rpc/jsonrpc/Defs.h          |    0
 {mgmt => include/mgmt}/rpc/jsonrpc/JsonRPC.h       |    0
 .../mgmt}/rpc/jsonrpc/JsonRPCManager.h             |    0
 .../mgmt}/rpc/jsonrpc/error/RPCError.h             |    0
 .../mgmt}/rpc/jsonrpc/json/YAMLCodec.h             |    0
 {mgmt => include/mgmt}/rpc/server/CommBase.h       |    0
 include/mgmt/rpc/server/IPCSocketServer.h          |  144 +
 {mgmt => include/mgmt}/rpc/server/RPCServer.h      |    0
 include/proxy/CacheControl.h                       |  130 +
 {proxy => include/proxy}/ControlBase.h             |    0
 {proxy => include/proxy}/ControlMatcher.h          |    0
 include/proxy/HostStatus.h                         |  239 +
 {proxy => include/proxy}/HttpAPIHooks.h            |    0
 {proxy => include/proxy}/IPAllow.h                 |    0
 include/proxy/Milestones.h                         |  104 +
 {proxy => include/proxy}/ParentConsistentHash.h    |    0
 {proxy => include/proxy}/ParentRoundRobin.h        |    0
 include/proxy/ParentSelection.h                    |  482 ++
 {proxy => include/proxy}/Plugin.h                  |    0
 include/proxy/PluginVC.h                           |  276 +
 {proxy => include/proxy}/PoolableSession.h         |    0
 include/proxy/ProtocolProbeSessionAccept.h         |   72 +
 {proxy => include/proxy}/ProxySession.h            |    0
 {proxy => include/proxy}/ProxyTransaction.h        |    0
 include/proxy/RegressionSM.h                       |   78 +
 include/proxy/ReverseProxy.h                       |   60 +
 {proxy => include/proxy}/Show.h                    |    0
 include/proxy/StatPages.h                          |  121 +
 include/proxy/Transform.h                          |  107 +
 {proxy => include/proxy}/TransformInternal.h       |    0
 {proxy => include/proxy}/hdrs/HTTP.h               |    0
 {proxy => include/proxy}/hdrs/HdrHeap.h            |    0
 {proxy => include/proxy}/hdrs/HdrToken.h           |    0
 {proxy => include/proxy}/hdrs/HdrUtils.h           |    0
 {proxy => include/proxy}/hdrs/HeaderValidator.h    |    0
 {proxy => include/proxy}/hdrs/HttpCompat.h         |    0
 {proxy => include/proxy}/hdrs/HuffmanCodec.h       |    0
 {proxy => include/proxy}/hdrs/MIME.h               |    0
 {proxy => include/proxy}/hdrs/URL.h                |    0
 {proxy => include/proxy}/hdrs/VersionConverter.h   |    0
 {proxy => include/proxy}/hdrs/XPACK.h              |    0
 {proxy => include/proxy}/http/ConnectingEntry.h    |    0
 {proxy => include/proxy}/http/Http1ClientSession.h |    0
 .../proxy}/http/Http1ClientTransaction.h           |    0
 {proxy => include/proxy}/http/Http1ServerSession.h |    0
 .../proxy}/http/Http1ServerTransaction.h           |    0
 {proxy => include/proxy}/http/Http1Transaction.h   |    0
 {proxy => include/proxy}/http/HttpBodyFactory.h    |    0
 include/proxy/http/HttpCacheSM.h                   |  244 +
 include/proxy/http/HttpConfig.h                    |  860 ++
 .../proxy}/http/HttpConnectionCount.h              |    0
 {proxy => include/proxy}/http/HttpDebugNames.h     |    0
 include/proxy/http/HttpPages.h                     |   86 +
 {proxy => include/proxy}/http/HttpProxyAPIEnums.h  |    0
 .../proxy}/http/HttpProxyServerMain.h              |    0
 include/proxy/http/HttpSM.h                        |  814 ++
 include/proxy/http/HttpSessionAccept.h             |  197 +
 include/proxy/http/HttpSessionManager.h            |  140 +
 include/proxy/http/HttpTransact.h                  | 1156 +++
 .../proxy}/http/HttpTransactHeaders.h              |    0
 include/proxy/http/HttpTunnel.h                    |  626 ++
 include/proxy/http/HttpUserAgent.h                 |  268 +
 include/proxy/http/HttpVCTable.h                   |   83 +
 {proxy => include/proxy}/http/PreWarmAlgorithm.h   |    0
 {proxy => include/proxy}/http/PreWarmConfig.h      |    0
 include/proxy/http/PreWarmManager.h                |  339 +
 {proxy => include/proxy}/http/remap/AclFiltering.h |    0
 .../proxy}/http/remap/NextHopConsistentHash.h      |    0
 .../proxy}/http/remap/NextHopRoundRobin.h          |    0
 .../proxy}/http/remap/NextHopSelectionStrategy.h   |    0
 .../proxy}/http/remap/NextHopStrategyFactory.h     |    0
 include/proxy/http/remap/PluginDso.h               |  176 +
 .../proxy}/http/remap/PluginFactory.h              |    0
 {proxy => include/proxy}/http/remap/RemapConfig.h  |    0
 include/proxy/http/remap/RemapHitCount.h           |   30 +
 .../proxy}/http/remap/RemapPluginInfo.h            |    0
 include/proxy/http/remap/RemapPlugins.h            |   69 +
 include/proxy/http/remap/RemapProcessor.h          |   53 +
 {proxy => include/proxy}/http/remap/UrlMapping.h   |    0
 .../proxy}/http/remap/UrlMappingPathIndex.h        |    0
 {proxy => include/proxy}/http/remap/UrlRewrite.h   |    0
 {proxy => include/proxy}/http2/HPACK.h             |    0
 include/proxy/http2/HTTP2.h                        |  427 +
 .../proxy}/http2/Http2ClientSession.h              |    0
 .../proxy}/http2/Http2CommonSession.h              |    0
 .../proxy}/http2/Http2CommonSessionInternal.h      |    0
 .../proxy}/http2/Http2ConnectionState.h            |    0
 {proxy => include/proxy}/http2/Http2DebugNames.h   |    0
 .../proxy}/http2/Http2DependencyTree.h             |    0
 include/proxy/http2/Http2Frame.h                   |  256 +
 include/proxy/http2/Http2FrequencyCounter.h        |   42 +
 .../proxy}/http2/Http2ServerSession.h              |    0
 include/proxy/http2/Http2SessionAccept.h           |   54 +
 {proxy => include/proxy}/http2/Http2Stream.h       |    0
 {proxy => include/proxy}/http3/Http09App.h         |    0
 {proxy => include/proxy}/http3/Http3.h             |    0
 {proxy => include/proxy}/http3/Http3App.h          |    0
 {proxy => include/proxy}/http3/Http3Config.h       |    0
 {proxy => include/proxy}/http3/Http3DataFramer.h   |    0
 {proxy => include/proxy}/http3/Http3DebugNames.h   |    0
 {proxy => include/proxy}/http3/Http3Frame.h        |    0
 .../proxy}/http3/Http3FrameCollector.h             |    0
 .../proxy}/http3/Http3FrameDispatcher.h            |    0
 .../proxy}/http3/Http3FrameGenerator.h             |    0
 {proxy => include/proxy}/http3/Http3FrameHandler.h |    0
 {proxy => include/proxy}/http3/Http3HeaderFramer.h |    0
 .../proxy}/http3/Http3HeaderVIOAdaptor.h           |    0
 .../proxy}/http3/Http3ProtocolEnforcer.h           |    0
 {proxy => include/proxy}/http3/Http3Session.h      |    0
 include/proxy/http3/Http3SessionAccept.h           |   54 +
 .../proxy}/http3/Http3SettingsHandler.h            |    0
 .../proxy}/http3/Http3StreamDataVIOAdaptor.h       |    0
 include/proxy/http3/Http3Transaction.h             |  164 +
 {proxy => include/proxy}/http3/Http3Types.h        |    0
 include/proxy/http3/QPACK.h                        |  342 +
 include/proxy/logging/Log.h                        |  235 +
 {proxy => include/proxy}/logging/LogAccess.h       |    0
 {proxy => include/proxy}/logging/LogBuffer.h       |    0
 {proxy => include/proxy}/logging/LogBufferSink.h   |    0
 include/proxy/logging/LogConfig.h                  |  222 +
 {proxy => include/proxy}/logging/LogField.h        |    0
 .../proxy}/logging/LogFieldAliasMap.h              |    0
 {proxy => include/proxy}/logging/LogFile.h         |    0
 {proxy => include/proxy}/logging/LogFilter.h       |    0
 {proxy => include/proxy}/logging/LogFormat.h       |    0
 {proxy => include/proxy}/logging/LogLimits.h       |    0
 {proxy => include/proxy}/logging/LogObject.h       |    0
 {proxy => include/proxy}/logging/LogUtils.h        |    0
 .../proxy}/logging/RolledLogDeleter.h              |    0
 {proxy => include/proxy}/logging/YamlLogConfig.h   |    0
 .../proxy}/logging/YamlLogConfigDecoders.h         |    0
 {proxy => include/proxy}/shared/DiagsConfig.h      |    0
 include/records/I_RecCore.h                        |  262 -
 include/records/I_RecDefs.h                        |  184 -
 include/records/I_RecLocal.h                       |   36 -
 include/records/I_RecProcess.h                     |  146 -
 include/records/P_RecCore.h                        |    2 +-
 include/records/P_RecDefs.h                        |    2 +-
 include/records/P_RecProcess.h                     |    2 +-
 include/records/RecCore.h                          |  262 +
 include/records/RecDefs.h                          |  184 +
 include/records/{I_RecHttp.h => RecHttp.h}         |    0
 include/records/RecLocal.h                         |   36 +
 include/records/{I_RecMutex.h => RecMutex.h}       |    0
 include/records/RecProcess.h                       |  146 +
 .../records/{I_RecordsConfig.h => RecordsConfig.h} |    0
 include/shared/rpc/RPCClient.h                     |    2 +-
 include/ts/InkAPIPrivateIOCore.h                   |    4 +-
 include/tscore/{I_Layout.h => Layout.h}            |    0
 include/tscore/{I_Version.h => Version.h}          |    0
 iocore/CMakeLists.txt                              |   39 -
 iocore/aio/AIO.cc                                  |  633 --
 iocore/aio/AIO_fault_injection.cc                  |  122 -
 iocore/aio/AIO_fault_injection.h                   |   72 -
 iocore/aio/CMakeLists.txt                          |   32 -
 iocore/aio/I_AIO.h                                 |   85 -
 iocore/aio/P_AIO.h                                 |  142 -
 iocore/aio/test_AIO.cc                             |  557 --
 iocore/cache/CMakeLists.txt                        |   66 -
 iocore/cache/Cache.cc                              | 1960 -----
 iocore/cache/CacheEvacuateDocVC.cc                 |  211 -
 iocore/cache/CacheEvacuateDocVC.h                  |   72 -
 iocore/cache/CacheHosting.cc                       | 1126 ---
 iocore/cache/CachePages.cc                         |  694 --
 iocore/cache/CachePagesInternal.cc                 |  342 -
 iocore/cache/CacheVC.cc                            | 1086 ---
 iocore/cache/CacheVC.h                             |  335 -
 iocore/cache/I_Cache.h                             |  223 -
 iocore/cache/I_CacheDefs.h                         |  143 -
 iocore/cache/P_Cache.h                             |   42 -
 iocore/cache/P_CacheDir.h                          |  338 -
 iocore/cache/P_CacheDisk.h                         |  125 -
 iocore/cache/P_RamCache.h                          |   44 -
 iocore/cache/RamCacheCLFUS.cc                      |  790 --
 iocore/cache/Store.cc                              |  511 --
 iocore/cache/Vol.cc                                |  918 --
 iocore/cache/test/CacheTestHandler.cc              |   86 -
 iocore/cache/test/main.cc                          |  367 -
 iocore/cache/test/main.h                           |  258 -
 iocore/cache/test/stub.cc                          |   83 -
 iocore/dns/CMakeLists.txt                          |   26 -
 iocore/dns/DNS.cc                                  | 1989 -----
 iocore/dns/I_DNS.h                                 |   36 -
 iocore/dns/I_DNSProcessor.h                        |  231 -
 iocore/dns/I_SplitDNS.h                            |   36 -
 iocore/dns/P_DNS.h                                 |   38 -
 iocore/dns/P_DNSConnection.h                       |  150 -
 iocore/dns/P_DNSProcessor.h                        |  314 -
 iocore/dns/P_SplitDNS.h                            |   40 -
 iocore/dns/test_I_DNS.cc                           |   43 -
 iocore/eventsystem/CMakeLists.txt                  |   53 -
 iocore/eventsystem/ConfigProcessor.h               |  117 -
 iocore/eventsystem/EventSystem.cc                  |   66 -
 iocore/eventsystem/I_Action.h                      |  196 -
 iocore/eventsystem/I_Continuation.h                |  281 -
 iocore/eventsystem/I_EThread.h                     |  644 --
 iocore/eventsystem/I_Event.h                       |  292 -
 iocore/eventsystem/I_EventProcessor.h              |  402 -
 iocore/eventsystem/I_EventSystem.h                 |   51 -
 iocore/eventsystem/I_Lock.h                        |  681 --
 iocore/eventsystem/I_MIOBufferWriter.h             |  189 -
 iocore/eventsystem/I_PriorityEventQueue.h          |  122 -
 iocore/eventsystem/I_ProtectedQueue.h              |   54 -
 iocore/eventsystem/I_Tasks.h                       |   38 -
 iocore/eventsystem/I_Thread.h                      |  170 -
 iocore/eventsystem/I_VConnection.h                 |  413 -
 iocore/eventsystem/I_VIO.h                         |  223 -
 iocore/eventsystem/MIOBufferWriter.cc              |  124 -
 iocore/eventsystem/P_EventSystem.h                 |   50 -
 iocore/eventsystem/P_Freer.h                       |  134 -
 iocore/eventsystem/P_ProtectedQueue.h              |   83 -
 iocore/eventsystem/P_Thread.h                      |   49 -
 iocore/eventsystem/P_UnixEThread.h                 |  261 -
 iocore/eventsystem/P_UnixEventProcessor.h          |  200 -
 iocore/eventsystem/P_UnixSocketManager.h           |  291 -
 iocore/eventsystem/P_VConnection.h                 |   95 -
 iocore/eventsystem/P_VIO.h                         |  123 -
 iocore/eventsystem/ProxyAllocator.cc               |   61 -
 iocore/eventsystem/RecProcess.cc                   |  194 -
 iocore/eventsystem/RecProcess.h                    |   40 -
 iocore/eventsystem/RecRawStatsImpl.cc              |  257 -
 iocore/eventsystem/Tasks.cc                        |   44 -
 iocore/eventsystem/unit_tests/test_EventSystem.cc  |  119 -
 iocore/eventsystem/unit_tests/test_IOBuffer.cc     |  398 -
 .../eventsystem/unit_tests/test_MIOBufferWriter.cc |  200 -
 iocore/hostdb/CMakeLists.txt                       |   28 -
 iocore/hostdb/HostDB.cc                            | 2160 -----
 iocore/hostdb/HostDBInfo.cc                        |   84 -
 iocore/hostdb/HostFile.h                           |   52 -
 iocore/hostdb/I_HostDB.h                           |   41 -
 iocore/hostdb/I_HostDBProcessor.h                  |  887 --
 iocore/hostdb/P_HostDB.h                           |   49 -
 iocore/hostdb/P_HostDBProcessor.h                  |  313 -
 iocore/hostdb/P_RefCountCache.h                    |  600 --
 iocore/hostdb/test_I_HostDB.cc                     |   50 -
 iocore/hostdb/test_RefCountCache.cc                |  293 -
 iocore/io_uring/IOUringEventIO.cc                  |   41 -
 iocore/io_uring/io_uring.cc                        |  226 -
 iocore/io_uring/unit_tests/test_diskIO.cc          |  282 -
 iocore/net/ALPNSupport.cc                          |  146 -
 iocore/net/AcceptOptions.h                         |   90 -
 iocore/net/AsyncSignalEventIO.cc                   |   48 -
 iocore/net/BIO_fastopen.cc                         |  212 -
 iocore/net/CMakeLists.txt                          |  134 -
 iocore/net/I_Net.h                                 |   91 -
 iocore/net/I_NetProcessor.h                        |  184 -
 iocore/net/I_NetVConnection.h                      |  703 --
 iocore/net/I_SessionAccept.h                       |   79 -
 iocore/net/I_UDPConnection.h                       |  114 -
 iocore/net/I_UDPNet.h                              |  111 -
 iocore/net/I_UDPPacket.h                           |  158 -
 iocore/net/NetEvent.h                              |  141 -
 iocore/net/NetHandler.cc                           |  585 --
 iocore/net/NetHandler.h                            |  236 -
 iocore/net/NetTimeout.h                            |  263 -
 iocore/net/NetVCOptions.cc                         |   70 -
 iocore/net/NetVCOptions.h                          |  318 -
 iocore/net/P_ALPNSupport.h                         |  104 -
 iocore/net/P_Net.h                                 |  114 -
 iocore/net/P_NetAccept.h                           |  126 -
 iocore/net/P_NetVConnection.h                      |  104 -
 iocore/net/P_QUICNetVConnection_native.h           |  400 -
 iocore/net/P_QUICNetVConnection_quiche.h           |  218 -
 iocore/net/P_QUICNextProtocolAccept_native.h       |   59 -
 iocore/net/P_QUICNextProtocolAccept_quiche.h       |   59 -
 iocore/net/P_SNIActionPerformer.h                  |  582 --
 iocore/net/P_SSLNetVConnection.h                   |  510 --
 iocore/net/P_SSLNextProtocolAccept.h               |   66 -
 iocore/net/P_SSLNextProtocolSet.h                  |   62 -
 iocore/net/P_SSLUtils.h                            |  216 -
 iocore/net/P_Socks.h                               |  142 -
 iocore/net/P_UDPConnection.h                       |  134 -
 iocore/net/P_UDPNet.h                              |  367 -
 iocore/net/P_UnixNetProcessor.h                    |   68 -
 iocore/net/P_UnixNetState.h                        |   54 -
 iocore/net/P_UnixNetVConnection.h                  |  360 -
 iocore/net/PollCont.h                              |   43 -
 iocore/net/PreWarm.h                               |   50 -
 iocore/net/ProxyProtocol.cc                        |  508 --
 iocore/net/QUICNetProcessor.cc                     |  229 -
 iocore/net/QUICNetProcessor_quiche.cc              |  252 -
 iocore/net/QUICNetVConnection.cc                   | 2461 ------
 iocore/net/QUICPacketHandler_quiche.cc             |  348 -
 iocore/net/SSLCertLookup.cc                        |  587 --
 iocore/net/SSLClientUtils.cc                       |  324 -
 iocore/net/SSLConfig.cc                            | 1034 ---
 iocore/net/SSLNetProcessor.cc                      |  108 -
 iocore/net/SSLNetVConnection.cc                    | 2647 ------
 iocore/net/SSLSNIConfig.cc                         |  403 -
 iocore/net/SSLSessionCache.h                       |  218 -
 iocore/net/SSLStats.h                              |  106 -
 iocore/net/SSLUtils.cc                             | 2619 ------
 iocore/net/Socks.cc                                |  696 --
 iocore/net/UnixNet.cc                              |  201 -
 iocore/net/UnixNetPages.cc                         |  247 -
 iocore/net/UnixUDPNet.cc                           | 1835 ----
 iocore/net/YamlSNIConfig.cc                        |  554 --
 iocore/net/quic/CMakeLists.txt                     |   39 -
 iocore/net/quic/QUICAckFrameCreator.cc             |  391 -
 iocore/net/quic/QUICApplication.h                  |   50 -
 iocore/net/quic/QUICConfig.cc                      |  519 --
 iocore/net/quic/QUICConnection.h                   |   75 -
 iocore/net/quic/QUICDebugNames.cc                  |  343 -
 iocore/net/quic/QUICEvents.h                       |   39 -
 iocore/net/quic/QUICFlowController.h               |  156 -
 iocore/net/quic/QUICFrame.h                        |  911 --
 iocore/net/quic/QUICLossDetector.h                 |  183 -
 iocore/net/quic/QUICPacket.h                       |  561 --
 iocore/net/quic/QUICPacketPayloadProtector.h       |   53 -
 iocore/net/quic/QUICPacketReceiveQueue.cc          |  200 -
 iocore/net/quic/QUICPacketReceiveQueue.h           |   56 -
 iocore/net/quic/QUICPadder.h                       |   57 -
 iocore/net/quic/QUICPinger.h                       |   52 -
 iocore/net/quic/QUICStream.h                       |  106 -
 iocore/net/quic/QUICStreamVCAdapter.cc             |  322 -
 iocore/net/quic/QUICStreamVCAdapter.h              |  106 -
 iocore/net/quic/QUICTLS.h                          |  128 -
 iocore/net/quic/QUICTransferProgressProvider.cc    |   83 -
 iocore/net/quic/QUICTypes.cc                       |  861 --
 iocore/net/quic/QUICTypes.h                        |  673 --
 iocore/net/quic/test/event_processor_main.cc       |   64 -
 iocore/net/quic/test/main.cc                       |   60 -
 iocore/net/quic/test/test_QUICType.cc              |  150 -
 iocore/net/test_I_UDPNet.cc                        |  234 -
 iocore/net/unit_tests/unit_test_main.cc            |   74 -
 iocore/utils/CMakeLists.txt                        |   26 -
 iocore/utils/I_OneWayMultiTunnel.h                 |  134 -
 iocore/utils/I_OneWayTunnel.h                      |  211 -
 iocore/utils/Machine.cc                            |  255 -
 iocore/utils/OneWayMultiTunnel.cc                  |  257 -
 iocore/utils/OneWayTunnel.cc                       |  391 -
 mgmt/config/CMakeLists.txt                         |   29 -
 mgmt/config/FileManager.cc                         |  435 -
 mgmt/rpc/CMakeLists.txt                            |   66 -
 mgmt/rpc/config/JsonRPCConfig.cc                   |  104 -
 mgmt/rpc/handlers/common/RecordsUtils.h            |  102 -
 mgmt/rpc/handlers/common/convert.h                 |  179 -
 mgmt/rpc/handlers/config/Configuration.cc          |  204 -
 mgmt/rpc/server/IPCSocketServer.cc                 |  525 --
 mgmt/rpc/server/IPCSocketServer.h                  |  144 -
 mgmt/rpc/server/unit_tests/test_rpcserver.cc       |  561 --
 plugins/experimental/memcache/tsmemcache.cc        |    4 +-
 plugins/experimental/memcache/tsmemcache.h         |    8 +-
 proxy/CMakeLists.txt                               |   76 -
 proxy/CacheControl.h                               |  130 -
 proxy/HostStatus.cc                                |  533 --
 proxy/HostStatus.h                                 |  239 -
 proxy/Milestones.h                                 |  104 -
 proxy/ParentSelection.cc                           | 1916 -----
 proxy/ParentSelection.h                            |  482 --
 proxy/Plugin.cc                                    |  367 -
 proxy/PluginVC.h                                   |  276 -
 proxy/ProtocolProbeSessionAccept.cc                |  216 -
 proxy/ProtocolProbeSessionAccept.h                 |   72 -
 proxy/RegressionSM.h                               |   78 -
 proxy/ReverseProxy.h                               |   60 -
 proxy/StatPages.h                                  |  121 -
 proxy/Transform.h                                  |  107 -
 proxy/hdrs/CMakeLists.txt                          |   67 -
 proxy/hdrs/HdrHeap.cc                              | 1202 ---
 proxy/hdrs/unit_tests/test_mime.cc                 |  251 -
 proxy/http/CMakeLists.txt                          |   80 -
 proxy/http/HttpBodyFactory.cc                      | 1165 ---
 proxy/http/HttpCacheSM.h                           |  244 -
 proxy/http/HttpConfig.cc                           | 1498 ----
 proxy/http/HttpConfig.h                            |  860 --
 proxy/http/HttpDebugNames.cc                       |  664 --
 proxy/http/HttpPages.h                             |   86 -
 proxy/http/HttpSM.cc                               | 8797 -------------------
 proxy/http/HttpSM.h                                |  814 --
 proxy/http/HttpSessionAccept.cc                    |   90 -
 proxy/http/HttpSessionAccept.h                     |  197 -
 proxy/http/HttpSessionManager.h                    |  140 -
 proxy/http/HttpTransact.cc                         | 8905 --------------------
 proxy/http/HttpTransact.h                          | 1156 ---
 proxy/http/HttpTransactHeaders.cc                  | 1306 ---
 proxy/http/HttpTunnel.h                            |  626 --
 proxy/http/HttpUserAgent.h                         |  268 -
 proxy/http/HttpVCTable.cc                          |  136 -
 proxy/http/HttpVCTable.h                           |   83 -
 proxy/http/PreWarmManager.cc                       | 1173 ---
 proxy/http/PreWarmManager.h                        |  339 -
 proxy/http/remap/CMakeLists.txt                    |   49 -
 proxy/http/remap/NextHopConsistentHash.cc          |  512 --
 proxy/http/remap/NextHopSelectionStrategy.cc       |  424 -
 proxy/http/remap/PluginDso.h                       |  176 -
 proxy/http/remap/RemapConfig.cc                    | 1365 ---
 proxy/http/remap/RemapHitCount.h                   |   30 -
 proxy/http/remap/RemapPlugins.h                    |   69 -
 proxy/http/remap/RemapProcessor.h                  |   53 -
 proxy/http/remap/UrlMapping.cc                     |  204 -
 proxy/http/remap/UrlRewrite.cc                     |  966 ---
 proxy/http/remap/unit-tests/nexthop_test_stubs.cc  |  211 -
 proxy/http/remap/unit-tests/test_PluginFactory.cc  | 1429 ----
 proxy/http/unit_tests/CMakeLists.txt               |   45 -
 proxy/http/unit_tests/main.cc                      |   60 -
 proxy/http/unit_tests/test_HttpTransact.cc         |  590 --
 proxy/http/unit_tests/test_HttpUserAgent.cc        |   93 -
 proxy/http/unit_tests/unit_test_main.cc            |   30 -
 proxy/http2/CMakeLists.txt                         |   76 -
 proxy/http2/HTTP2.h                                |  427 -
 proxy/http2/Http2Frame.h                           |  256 -
 proxy/http2/Http2FrequencyCounter.h                |   42 -
 proxy/http2/Http2SessionAccept.cc                  |   90 -
 proxy/http2/Http2SessionAccept.h                   |   54 -
 proxy/http2/test_HPACK.cc                          |  429 -
 proxy/http2/unit_tests/main.cc                     |   65 -
 proxy/http3/CMakeLists.txt                         |   87 -
 proxy/http3/Http3HeaderFramer.cc                   |  115 -
 proxy/http3/Http3HeaderVIOAdaptor.cc               |  149 -
 proxy/http3/Http3SessionAccept.cc                  |  101 -
 proxy/http3/Http3SessionAccept.h                   |   54 -
 proxy/http3/Http3StreamDataVIOAdaptor.cc           |   74 -
 proxy/http3/Http3Transaction.h                     |  164 -
 proxy/http3/QPACK.h                                |  342 -
 proxy/http3/test/main.cc                           |   62 -
 proxy/http3/test/main_qpack.cc                     |  107 -
 proxy/logging/CMakeLists.txt                       |   53 -
 proxy/logging/Log.cc                               | 1413 ----
 proxy/logging/Log.h                                |  235 -
 proxy/logging/LogAccess.cc                         | 3297 --------
 proxy/logging/LogConfig.cc                         |  815 --
 proxy/logging/LogConfig.h                          |  222 -
 proxy/logging/LogFile.cc                           |  772 --
 proxy/logging/LogStandalone.cc                     |  210 -
 proxy/logging/unit-tests/benchmark_LogObject.cc    |  194 -
 proxy/private/SSLProxySession.cc                   |   39 -
 proxy/shared/DiagsConfig.cc                        |  378 -
 src/api/APIHook.cc                                 |    4 +-
 src/api/APIHooks.cc                                |    4 +-
 src/api/CMakeLists.txt                             |   19 +-
 src/api/InkAPI.cc                                  |   18 +-
 src/api/InkAPITest.cc                              |    4 +-
 src/api/InkContInternal.cc                         |   12 +-
 src/api/InkIOCoreAPI.cc                            |    8 +-
 src/iocore/CMakeLists.txt                          |   39 +
 {iocore => src/iocore}/Makefile.am                 |    0
 src/iocore/aio/AIO.cc                              |  633 ++
 src/iocore/aio/AIO_fault_injection.cc              |  122 +
 src/iocore/aio/CMakeLists.txt                      |   32 +
 {iocore => src/iocore}/aio/Inline.cc               |    0
 {iocore => src/iocore}/aio/Makefile.am             |    0
 src/iocore/aio/P_AIO.h                             |  142 +
 {iocore => src/iocore}/aio/sample.cfg              |    0
 src/iocore/aio/test_AIO.cc                         |  557 ++
 {iocore => src/iocore}/aio/test_AIO.sample         |    0
 src/iocore/cache/CMakeLists.txt                    |   72 +
 src/iocore/cache/Cache.cc                          | 1960 +++++
 {iocore => src/iocore}/cache/CacheDir.cc           |    0
 {iocore => src/iocore}/cache/CacheDisk.cc          |    0
 src/iocore/cache/CacheEvacuateDocVC.cc             |  211 +
 src/iocore/cache/CacheHosting.cc                   | 1126 +++
 {iocore => src/iocore}/cache/CacheHttp.cc          |    0
 src/iocore/cache/CachePages.cc                     |  694 ++
 src/iocore/cache/CachePagesInternal.cc             |  342 +
 {iocore => src/iocore}/cache/CacheRead.cc          |    0
 {iocore => src/iocore}/cache/CacheTest.cc          |    0
 src/iocore/cache/CacheVC.cc                        | 1086 +++
 {iocore => src/iocore}/cache/CacheVol.cc           |    0
 {iocore => src/iocore}/cache/CacheWrite.cc         |    0
 {iocore => src/iocore}/cache/HttpTransactCache.cc  |    0
 {iocore => src/iocore}/cache/Makefile.am           |    0
 {iocore => src/iocore}/cache/Notes                 |    0
 src/iocore/cache/P_Cache.h                         |   42 +
 {iocore => src/iocore}/cache/P_CacheArray.h        |    0
 src/iocore/cache/P_CacheDir.h                      |  338 +
 src/iocore/cache/P_CacheDisk.h                     |  125 +
 {iocore => src/iocore}/cache/P_CacheHosting.h      |    0
 {iocore => src/iocore}/cache/P_CacheHttp.h         |    0
 {iocore => src/iocore}/cache/P_CacheInternal.h     |    0
 {iocore => src/iocore}/cache/P_CacheStats.h        |    0
 {iocore => src/iocore}/cache/P_CacheTest.h         |    0
 {iocore => src/iocore}/cache/P_CacheVol.h          |    0
 src/iocore/cache/P_RamCache.h                      |   44 +
 src/iocore/cache/RamCacheCLFUS.cc                  |  790 ++
 {iocore => src/iocore}/cache/RamCacheLRU.cc        |    0
 src/iocore/cache/Store.cc                          |  511 ++
 src/iocore/cache/Vol.cc                            |  918 ++
 src/iocore/cache/test/CacheTestHandler.cc          |   86 +
 .../iocore}/cache/test/CacheTestHandler.h          |    0
 src/iocore/cache/test/main.cc                      |  367 +
 src/iocore/cache/test/main.h                       |  258 +
 {iocore => src/iocore}/cache/test/storage.config   |    0
 src/iocore/cache/test/stub.cc                      |   83 +
 .../iocore}/cache/test/test_Alternate_L_to_S.cc    |    0
 .../cache/test/test_Alternate_L_to_S_remove_L.cc   |    0
 .../cache/test/test_Alternate_L_to_S_remove_S.cc   |    0
 .../iocore}/cache/test/test_Alternate_S_to_L.cc    |    0
 .../cache/test/test_Alternate_S_to_L_remove_L.cc   |    0
 .../cache/test/test_Alternate_S_to_L_remove_S.cc   |    0
 {iocore => src/iocore}/cache/test/test_Cache.cc    |    0
 .../iocore}/cache/test/test_Disk_Failure.cc        |    0
 .../iocore}/cache/test/test_Disk_Init_Failure.cc   |    0
 .../iocore}/cache/test/test_Populated_Cache.cc     |    0
 .../test/test_Populated_Cache_Disk_Failure.cc      |    0
 {iocore => src/iocore}/cache/test/test_RWW.cc      |    0
 .../iocore}/cache/test/test_Update_L_to_S.cc       |    0
 .../iocore}/cache/test/test_Update_S_to_L.cc       |    0
 .../iocore}/cache/test/test_Update_header.cc       |    0
 .../iocore}/cache/test/var/trafficserver/guard.txt |    0
 src/iocore/dns/CMakeLists.txt                      |   34 +
 src/iocore/dns/DNS.cc                              | 1989 +++++
 {iocore => src/iocore}/dns/DNSConnection.cc        |    0
 {iocore => src/iocore}/dns/DNSEventIO.cc           |    0
 {iocore => src/iocore}/dns/Inline.cc               |    0
 {iocore => src/iocore}/dns/Makefile.am             |    0
 src/iocore/dns/P_DNS.h                             |   38 +
 src/iocore/dns/P_DNSConnection.h                   |  150 +
 src/iocore/dns/P_DNSProcessor.h                    |  314 +
 src/iocore/dns/P_SplitDNS.h                        |   40 +
 {iocore => src/iocore}/dns/P_SplitDNSProcessor.h   |    0
 {iocore => src/iocore}/dns/SplitDNS.cc             |    0
 src/iocore/dns/test_I_DNS.cc                       |   43 +
 {iocore => src/iocore}/dns/test_P_DNS.cc           |    0
 src/iocore/eventsystem/CMakeLists.txt              |   55 +
 .../iocore}/eventsystem/ConfigProcessor.cc         |    0
 src/iocore/eventsystem/EventSystem.cc              |   66 +
 {iocore => src/iocore}/eventsystem/IOBuffer.cc     |    0
 {iocore => src/iocore}/eventsystem/Inline.cc       |    0
 {iocore => src/iocore}/eventsystem/Lock.cc         |    0
 src/iocore/eventsystem/MIOBufferWriter.cc          |  124 +
 {iocore => src/iocore}/eventsystem/Makefile.am     |    0
 {iocore => src/iocore}/eventsystem/PQ-List.cc      |    0
 src/iocore/eventsystem/P_EventSystem.h             |   50 +
 src/iocore/eventsystem/P_Freer.h                   |  134 +
 {iocore => src/iocore}/eventsystem/P_IOBuffer.h    |    0
 src/iocore/eventsystem/P_ProtectedQueue.h          |   83 +
 src/iocore/eventsystem/P_Thread.h                  |   49 +
 src/iocore/eventsystem/P_UnixEThread.h             |  261 +
 {iocore => src/iocore}/eventsystem/P_UnixEvent.h   |    0
 src/iocore/eventsystem/P_UnixEventProcessor.h      |  200 +
 src/iocore/eventsystem/P_UnixSocketManager.h       |  291 +
 src/iocore/eventsystem/P_VConnection.h             |   95 +
 src/iocore/eventsystem/P_VIO.h                     |  123 +
 {iocore => src/iocore}/eventsystem/Processor.cc    |    0
 .../iocore}/eventsystem/ProtectedQueue.cc          |    0
 src/iocore/eventsystem/ProxyAllocator.cc           |   61 +
 src/iocore/eventsystem/RecProcess.cc               |  194 +
 src/iocore/eventsystem/RecRawStatsImpl.cc          |  257 +
 .../iocore}/eventsystem/SocketManager.cc           |    0
 src/iocore/eventsystem/Tasks.cc                    |   44 +
 {iocore => src/iocore}/eventsystem/Thread.cc       |    0
 {iocore => src/iocore}/eventsystem/UnixEThread.cc  |    0
 {iocore => src/iocore}/eventsystem/UnixEvent.cc    |    0
 .../iocore}/eventsystem/UnixEventProcessor.cc      |    0
 .../eventsystem/unit_tests/test_EventSystem.cc     |  119 +
 src/iocore/eventsystem/unit_tests/test_IOBuffer.cc |  398 +
 .../eventsystem/unit_tests/test_MIOBufferWriter.cc |  200 +
 src/iocore/hostdb/CMakeLists.txt                   |   36 +
 src/iocore/hostdb/HostDB.cc                        | 2160 +++++
 src/iocore/hostdb/HostDBInfo.cc                    |   84 +
 {iocore => src/iocore}/hostdb/HostFile.cc          |    0
 {iocore => src/iocore}/hostdb/Inline.cc            |    0
 {iocore => src/iocore}/hostdb/Makefile.am          |    0
 src/iocore/hostdb/P_HostDB.h                       |   49 +
 src/iocore/hostdb/P_HostDBProcessor.h              |  313 +
 src/iocore/hostdb/P_RefCountCache.h                |  600 ++
 {iocore => src/iocore}/hostdb/RefCountCache.cc     |    0
 {iocore => src/iocore}/hostdb/test_HostFile.cc     |    0
 src/iocore/hostdb/test_I_HostDB.cc                 |   50 +
 {iocore => src/iocore}/hostdb/test_P_HostDB.cc     |    0
 src/iocore/hostdb/test_RefCountCache.cc            |  293 +
 {iocore => src/iocore}/io_uring/CMakeLists.txt     |    0
 src/iocore/io_uring/IOUringEventIO.cc              |   41 +
 {iocore => src/iocore}/io_uring/Makefile.am        |    0
 {iocore => src/iocore}/io_uring/P_IO_URING.h       |    0
 src/iocore/io_uring/io_uring.cc                    |  226 +
 src/iocore/io_uring/unit_tests/test_diskIO.cc      |  282 +
 src/iocore/net/ALPNSupport.cc                      |  146 +
 src/iocore/net/AsyncSignalEventIO.cc               |   48 +
 src/iocore/net/BIO_fastopen.cc                     |  212 +
 {iocore => src/iocore}/net/BoringSSLUtils.cc       |    0
 src/iocore/net/CMakeLists.txt                      |  138 +
 {iocore => src/iocore}/net/Connection.cc           |    0
 {iocore => src/iocore}/net/EventIO.cc              |    0
 {iocore => src/iocore}/net/Inline.cc               |    0
 {iocore => src/iocore}/net/Makefile.am             |    0
 {iocore => src/iocore}/net/Net.cc                  |    0
 {iocore => src/iocore}/net/NetAcceptEventIO.cc     |    0
 src/iocore/net/NetHandler.cc                       |  585 ++
 src/iocore/net/NetVCOptions.cc                     |   70 +
 {iocore => src/iocore}/net/NetVCTest.cc            |    0
 {iocore => src/iocore}/net/NetVConnection.cc       |    0
 {iocore => src/iocore}/net/OCSPStapling.cc         |    0
 {iocore => src/iocore}/net/P_CompletionUtil.h      |    0
 {iocore => src/iocore}/net/P_Connection.h          |    0
 src/iocore/net/P_Net.h                             |  114 +
 src/iocore/net/P_NetAccept.h                       |  126 +
 {iocore => src/iocore}/net/P_NetVCTest.h           |    0
 src/iocore/net/P_NetVConnection.h                  |  104 +
 {iocore => src/iocore}/net/P_OCSPStapling.h        |    0
 .../iocore}/net/P_QUICClosedConCollector.h         |    0
 {iocore => src/iocore}/net/P_QUICNet.h             |    0
 {iocore => src/iocore}/net/P_QUICNetProcessor.h    |    0
 .../iocore}/net/P_QUICNetProcessor_native.h        |    0
 .../iocore}/net/P_QUICNetProcessor_quiche.h        |    0
 {iocore => src/iocore}/net/P_QUICNetVConnection.h  |    0
 src/iocore/net/P_QUICNetVConnection_native.h       |  400 +
 src/iocore/net/P_QUICNetVConnection_quiche.h       |  218 +
 .../iocore}/net/P_QUICNextProtocolAccept.h         |    0
 src/iocore/net/P_QUICNextProtocolAccept_native.h   |   59 +
 src/iocore/net/P_QUICNextProtocolAccept_quiche.h   |   59 +
 {iocore => src/iocore}/net/P_QUICPacketHandler.h   |    0
 .../iocore}/net/P_QUICPacketHandler_native.h       |    0
 .../iocore}/net/P_QUICPacketHandler_quiche.h       |    0
 src/iocore/net/P_SNIActionPerformer.h              |  582 ++
 {iocore => src/iocore}/net/P_SSLCertLookup.h       |    0
 .../iocore}/net/P_SSLClientCoordinator.h           |    0
 {iocore => src/iocore}/net/P_SSLClientUtils.h      |    0
 {iocore => src/iocore}/net/P_SSLConfig.h           |    0
 {iocore => src/iocore}/net/P_SSLNetAccept.h        |    0
 {iocore => src/iocore}/net/P_SSLNetProcessor.h     |    0
 src/iocore/net/P_SSLNetVConnection.h               |  510 ++
 src/iocore/net/P_SSLNextProtocolAccept.h           |   66 +
 src/iocore/net/P_SSLNextProtocolSet.h              |   62 +
 {iocore => src/iocore}/net/P_SSLSecret.h           |    0
 src/iocore/net/P_SSLUtils.h                        |  216 +
 src/iocore/net/P_Socks.h                           |  142 +
 {iocore => src/iocore}/net/P_TLSKeyLogger.h        |    0
 src/iocore/net/P_UDPConnection.h                   |  134 +
 {iocore => src/iocore}/net/P_UDPIOEvent.h          |    0
 src/iocore/net/P_UDPNet.h                          |  367 +
 {iocore => src/iocore}/net/P_UnixCompletionUtil.h  |    0
 {iocore => src/iocore}/net/P_UnixNet.h             |    0
 src/iocore/net/P_UnixNetProcessor.h                |   68 +
 src/iocore/net/P_UnixNetState.h                    |   54 +
 src/iocore/net/P_UnixNetVConnection.h              |  360 +
 {iocore => src/iocore}/net/P_UnixPollDescriptor.h  |    0
 {iocore => src/iocore}/net/P_UnixUDPConnection.h   |    0
 {iocore => src/iocore}/net/PollCont.cc             |    0
 src/iocore/net/ProxyProtocol.cc                    |  508 ++
 .../iocore}/net/QUICClosedConCollector.cc          |    0
 .../iocore}/net/QUICMultiCertConfigLoader.cc       |    0
 {iocore => src/iocore}/net/QUICNet.cc              |    0
 src/iocore/net/QUICNetProcessor.cc                 |  229 +
 src/iocore/net/QUICNetProcessor_quiche.cc          |  252 +
 src/iocore/net/QUICNetVConnection.cc               | 2461 ++++++
 .../iocore}/net/QUICNetVConnection_quiche.cc       |    0
 .../iocore}/net/QUICNextProtocolAccept.cc          |    0
 .../iocore}/net/QUICNextProtocolAccept_quiche.cc   |    0
 {iocore => src/iocore}/net/QUICPacketHandler.cc    |    0
 src/iocore/net/QUICPacketHandler_quiche.cc         |  348 +
 {iocore => src/iocore}/net/QUICSupport.cc          |    0
 {iocore => src/iocore}/net/ReadWriteEventIO.cc     |    0
 {iocore => src/iocore}/net/SNIActionPerformer.cc   |    0
 {iocore => src/iocore}/net/SSLAPIHooks.cc          |    0
 src/iocore/net/SSLCertLookup.cc                    |  587 ++
 {iocore => src/iocore}/net/SSLClientCoordinator.cc |    0
 src/iocore/net/SSLClientUtils.cc                   |  324 +
 src/iocore/net/SSLConfig.cc                        | 1034 +++
 {iocore => src/iocore}/net/SSLDiags.cc             |    0
 {iocore => src/iocore}/net/SSLDynlock.cc           |    0
 {iocore => src/iocore}/net/SSLInternal.cc          |    0
 {iocore => src/iocore}/net/SSLNetAccept.cc         |    0
 src/iocore/net/SSLNetProcessor.cc                  |  108 +
 src/iocore/net/SSLNetVConnection.cc                | 2647 ++++++
 .../iocore}/net/SSLNextProtocolAccept.cc           |    0
 {iocore => src/iocore}/net/SSLNextProtocolSet.cc   |    0
 src/iocore/net/SSLSNIConfig.cc                     |  403 +
 {iocore => src/iocore}/net/SSLSecret.cc            |    0
 {iocore => src/iocore}/net/SSLSessionCache.cc      |    0
 {iocore => src/iocore}/net/SSLSessionTicket.cc     |    0
 {iocore => src/iocore}/net/SSLStats.cc             |    0
 src/iocore/net/SSLUtils.cc                         | 2619 ++++++
 src/iocore/net/Socks.cc                            |  696 ++
 {iocore => src/iocore}/net/TLSBasicSupport.cc      |    0
 {iocore => src/iocore}/net/TLSCertSwitchSupport.cc |    0
 {iocore => src/iocore}/net/TLSEarlyDataSupport.cc  |    0
 {iocore => src/iocore}/net/TLSKeyLogger.cc         |    0
 {iocore => src/iocore}/net/TLSSNISupport.cc        |    0
 .../iocore}/net/TLSSessionResumptionSupport.cc     |    0
 {iocore => src/iocore}/net/TLSTunnelSupport.cc     |    0
 {iocore => src/iocore}/net/UDPEventIO.cc           |    0
 {iocore => src/iocore}/net/UDPIOEvent.cc           |    0
 {iocore => src/iocore}/net/UnixConnection.cc       |    0
 src/iocore/net/UnixNet.cc                          |  201 +
 {iocore => src/iocore}/net/UnixNetAccept.cc        |    0
 src/iocore/net/UnixNetPages.cc                     |  247 +
 {iocore => src/iocore}/net/UnixNetProcessor.cc     |    0
 {iocore => src/iocore}/net/UnixNetVConnection.cc   |    0
 {iocore => src/iocore}/net/UnixUDPConnection.cc    |    0
 src/iocore/net/UnixUDPNet.cc                       | 1835 ++++
 src/iocore/net/YamlSNIConfig.cc                    |  554 ++
 {iocore => src/iocore}/net/libinknet_stub.cc       |    0
 src/iocore/net/quic/CMakeLists.txt                 |   44 +
 {iocore => src/iocore}/net/quic/Makefile.am        |    0
 src/iocore/net/quic/QUICAckFrameCreator.cc         |  391 +
 .../iocore}/net/quic/QUICAddrVerifyState.cc        |    0
 .../iocore}/net/quic/QUICAltConnectionManager.cc   |    0
 {iocore => src/iocore}/net/quic/QUICApplication.cc |    0
 .../iocore}/net/quic/QUICApplicationMap.cc         |    0
 .../iocore}/net/quic/QUICBidirectionalStream.cc    |    0
 src/iocore/net/quic/QUICConfig.cc                  |  519 ++
 .../iocore}/net/quic/QUICConnectionTable.cc        |    0
 {iocore => src/iocore}/net/quic/QUICContext.cc     |    0
 .../iocore}/net/quic/QUICCryptoStream.cc           |    0
 src/iocore/net/quic/QUICDebugNames.cc              |  343 +
 {iocore => src/iocore}/net/quic/QUICEchoApp.cc     |    0
 .../iocore}/net/quic/QUICFlowController.cc         |    0
 {iocore => src/iocore}/net/quic/QUICFrame.cc       |    0
 .../iocore}/net/quic/QUICFrameDispatcher.cc        |    0
 .../iocore}/net/quic/QUICFrameGenerator.cc         |    0
 .../iocore}/net/quic/QUICFrameRetransmitter.cc     |    0
 {iocore => src/iocore}/net/quic/QUICGlobals.cc     |    0
 {iocore => src/iocore}/net/quic/QUICHKDF.cc        |    0
 {iocore => src/iocore}/net/quic/QUICHandshake.cc   |    0
 .../iocore}/net/quic/QUICIncomingFrameBuffer.cc    |    0
 {iocore => src/iocore}/net/quic/QUICIntUtil.cc     |    0
 .../iocore}/net/quic/QUICKeyGenerator.cc           |    0
 .../iocore}/net/quic/QUICKeyGenerator_boringssl.cc |    0
 .../iocore}/net/quic/QUICKeyGenerator_openssl.cc   |    0
 .../iocore}/net/quic/QUICLossDetector.cc           |    0
 .../net/quic/QUICNewRenoCongestionController.cc    |    0
 {iocore => src/iocore}/net/quic/QUICPacket.cc      |    0
 .../iocore}/net/quic/QUICPacketFactory.cc          |    0
 .../iocore}/net/quic/QUICPacketHeaderProtector.cc  |    0
 .../quic/QUICPacketHeaderProtector_boringssl.cc    |    0
 .../net/quic/QUICPacketHeaderProtector_openssl.cc  |    0
 .../iocore}/net/quic/QUICPacketPayloadProtector.cc |    0
 .../quic/QUICPacketPayloadProtector_boringssl.cc   |    0
 .../net/quic/QUICPacketPayloadProtector_openssl.cc |    0
 .../net/quic/QUICPacketProtectionKeyInfo.cc        |    0
 src/iocore/net/quic/QUICPacketReceiveQueue.cc      |  200 +
 {iocore => src/iocore}/net/quic/QUICPadder.cc      |    0
 {iocore => src/iocore}/net/quic/QUICPathManager.cc |    0
 .../iocore}/net/quic/QUICPathValidator.cc          |    0
 {iocore => src/iocore}/net/quic/QUICPinger.cc      |    0
 .../iocore}/net/quic/QUICResetTokenTable.cc        |    0
 .../iocore}/net/quic/QUICRetryIntegrityTag.cc      |    0
 {iocore => src/iocore}/net/quic/QUICStream.cc      |    0
 .../iocore}/net/quic/QUICStreamAdapter.cc          |    0
 {iocore => src/iocore}/net/quic/QUICStreamBase.cc  |    0
 .../iocore}/net/quic/QUICStreamFactory.cc          |    0
 .../iocore}/net/quic/QUICStreamManager.cc          |    0
 .../iocore}/net/quic/QUICStreamManager_native.cc   |    0
 .../iocore}/net/quic/QUICStreamManager_quiche.cc   |    0
 {iocore => src/iocore}/net/quic/QUICStreamState.cc |    0
 src/iocore/net/quic/QUICStreamVCAdapter.cc         |  322 +
 .../iocore}/net/quic/QUICStream_quiche.cc          |    0
 {iocore => src/iocore}/net/quic/QUICTLS.cc         |    0
 .../iocore}/net/quic/QUICTLS_boringssl.cc          |    0
 {iocore => src/iocore}/net/quic/QUICTLS_openssl.cc |    0
 .../iocore}/net/quic/QUICTokenCreator.cc           |    0
 .../net/quic/QUICTransferProgressProvider.cc       |   83 +
 .../iocore}/net/quic/QUICTransportParameters.cc    |    0
 src/iocore/net/quic/QUICTypes.cc                   |  861 ++
 .../iocore}/net/quic/QUICUnidirectionalStream.cc   |    0
 .../iocore}/net/quic/QUICVersionNegotiator.cc      |    0
 {iocore => src/iocore}/net/quic/qlog/QLog.cc       |    0
 {iocore => src/iocore}/net/quic/qlog/QLogEvent.cc  |    0
 {iocore => src/iocore}/net/quic/qlog/QLogFrame.cc  |    0
 src/iocore/net/quic/test/event_processor_main.cc   |   64 +
 src/iocore/net/quic/test/main.cc                   |   60 +
 {iocore => src/iocore}/net/quic/test/server_cert.h |    0
 .../net/quic/test/test_QUICAckFrameCreator.cc      |    0
 .../net/quic/test/test_QUICAddrVerifyState.cc      |    0
 .../net/quic/test/test_QUICAltConnectionManager.cc |    0
 .../net/quic/test/test_QUICFlowController.cc       |    0
 .../iocore}/net/quic/test/test_QUICFrame.cc        |    0
 .../net/quic/test/test_QUICFrameDispatcher.cc      |    0
 .../net/quic/test/test_QUICFrameRetransmitter.cc   |    0
 .../net/quic/test/test_QUICHandshakeProtocol.cc    |    0
 .../net/quic/test/test_QUICIncomingFrameBuffer.cc  |    0
 .../iocore}/net/quic/test/test_QUICInvariants.cc   |    0
 .../iocore}/net/quic/test/test_QUICKeyGenerator.cc |    0
 .../iocore}/net/quic/test/test_QUICLossDetector.cc |    0
 .../iocore}/net/quic/test/test_QUICPacket.cc       |    0
 .../net/quic/test/test_QUICPacketFactory.cc        |    0
 .../quic/test/test_QUICPacketHeaderProtector.cc    |    0
 .../net/quic/test/test_QUICPathValidator.cc        |    0
 .../iocore}/net/quic/test/test_QUICPinger.cc       |    0
 .../iocore}/net/quic/test/test_QUICStream.cc       |    0
 .../net/quic/test/test_QUICStreamManager.cc        |    0
 .../iocore}/net/quic/test/test_QUICStreamState.cc  |    0
 .../net/quic/test/test_QUICTransportParameters.cc  |    0
 src/iocore/net/quic/test/test_QUICType.cc          |  150 +
 .../iocore}/net/quic/test/test_QUICTypeUtil.cc     |    0
 .../net/quic/test/test_QUICVersionNegotiator.cc    |    0
 .../iocore}/net/quic/test_MTHashTable.cc           |    0
 {iocore => src/iocore}/net/test_I_Net.cc           |    0
 src/iocore/net/test_I_UDPNet.cc                    |  234 +
 {iocore => src/iocore}/net/test_P_Net.cc           |    0
 {iocore => src/iocore}/net/test_certlookup.cc      |    0
 .../iocore}/net/unit_tests/sni_conf_test.yaml      |    0
 .../net/unit_tests/sni_conf_test_bad_port_0-1.yaml |    0
 .../sni_conf_test_bad_port_1-yowzers2.yaml         |    0
 .../net/unit_tests/sni_conf_test_bad_port_3-.yaml  |    0
 .../sni_conf_test_bad_port_65535-65536.yaml        |    0
 .../sni_conf_test_bad_port_8080-433.yaml           |    0
 .../sni_conf_test_bad_port_yowzers-1.yaml          |    0
 .../iocore}/net/unit_tests/test_ProxyProtocol.cc   |    0
 .../iocore}/net/unit_tests/test_SSLSNIConfig.cc    |    0
 .../iocore}/net/unit_tests/test_YamlSNIConfig.cc   |    0
 src/iocore/net/unit_tests/unit_test_main.cc        |   74 +
 src/iocore/utils/CMakeLists.txt                    |   32 +
 src/iocore/utils/Machine.cc                        |  255 +
 {iocore => src/iocore}/utils/Makefile.am           |    0
 src/iocore/utils/OneWayMultiTunnel.cc              |  257 +
 src/iocore/utils/OneWayTunnel.cc                   |  391 +
 {mgmt => src/mgmt}/Makefile.am                     |    0
 {mgmt => src/mgmt}/config/AddConfigFilesHere.cc    |    0
 src/mgmt/config/CMakeLists.txt                     |   36 +
 src/mgmt/config/FileManager.cc                     |  435 +
 {mgmt => src/mgmt}/config/Makefile.am              |    0
 src/mgmt/rpc/CMakeLists.txt                        |   86 +
 {mgmt => src/mgmt}/rpc/Makefile.am                 |    0
 src/mgmt/rpc/config/JsonRPCConfig.cc               |  104 +
 .../mgmt}/rpc/handlers/common/RecordsUtils.cc      |    0
 src/mgmt/rpc/handlers/config/Configuration.cc      |  204 +
 {mgmt => src/mgmt}/rpc/handlers/plugins/Plugins.cc |    0
 {mgmt => src/mgmt}/rpc/handlers/records/Records.cc |    0
 {mgmt => src/mgmt}/rpc/handlers/server/Server.cc   |    0
 {mgmt => src/mgmt}/rpc/handlers/storage/Storage.cc |    0
 {mgmt => src/mgmt}/rpc/jsonrpc/Context.cc          |    0
 {mgmt => src/mgmt}/rpc/jsonrpc/JsonRPCManager.cc   |    0
 {mgmt => src/mgmt}/rpc/jsonrpc/error/RPCError.cc   |    0
 .../rpc/jsonrpc/unit_tests/test_basic_protocol.cc  |    0
 .../mgmt}/rpc/jsonrpc/unit_tests/unit_test_main.cc |    0
 .../schema/admin_lookup_records_params_schema.json |    0
 .../mgmt}/rpc/schema/jsonrpc_request_schema.json   |    0
 .../mgmt}/rpc/schema/jsonrpc_response_schema.json  |    0
 .../mgmt}/rpc/schema/success_response_schema.json  |    0
 {mgmt => src/mgmt}/rpc/server/CommBase.cc          |    0
 src/mgmt/rpc/server/IPCSocketServer.cc             |  525 ++
 {mgmt => src/mgmt}/rpc/server/RPCServer.cc         |    0
 src/mgmt/rpc/server/unit_tests/test_rpcserver.cc   |  561 ++
 .../mgmt}/rpc/server/unit_tests/unit_test_main.cc  |    0
 src/proxy/CMakeLists.txt                           |   82 +
 {proxy => src/proxy}/CacheControl.cc               |    0
 {proxy => src/proxy}/ControlBase.cc                |    0
 {proxy => src/proxy}/ControlMatcher.cc             |    0
 src/proxy/HostStatus.cc                            |  533 ++
 {proxy => src/proxy}/HttpAPIHooks.cc               |    0
 {proxy => src/proxy}/IPAllow.cc                    |    0
 {proxy => src/proxy}/Makefile.am                   |    0
 {proxy => src/proxy}/ParentConsistentHash.cc       |    0
 {proxy => src/proxy}/ParentRoundRobin.cc           |    0
 src/proxy/ParentSelection.cc                       | 1916 +++++
 {proxy => src/proxy}/ParentSelectionStrategy.cc    |    0
 src/proxy/Plugin.cc                                |  367 +
 {proxy => src/proxy}/PluginVC.cc                   |    0
 src/proxy/ProtocolProbeSessionAccept.cc            |  216 +
 {proxy => src/proxy}/ProxySession.cc               |    0
 {proxy => src/proxy}/ProxyTransaction.cc           |    0
 {proxy => src/proxy}/README-stats.otl              |    0
 {proxy => src/proxy}/RegressionSM.cc               |    0
 {proxy => src/proxy}/ReverseProxy.cc               |    0
 {proxy => src/proxy}/StatPages.cc                  |    0
 {proxy => src/proxy}/Transform.cc                  |    0
 {proxy => src/proxy}/example_prep.sh               |    0
 src/proxy/hdrs/CMakeLists.txt                      |   67 +
 {proxy => src/proxy}/hdrs/HTTP.cc                  |    0
 src/proxy/hdrs/HdrHeap.cc                          | 1202 +++
 {proxy => src/proxy}/hdrs/HdrTSOnly.cc             |    0
 {proxy => src/proxy}/hdrs/HdrToken.cc              |    0
 {proxy => src/proxy}/hdrs/HdrUtils.cc              |    0
 {proxy => src/proxy}/hdrs/HeaderValidator.cc       |    0
 {proxy => src/proxy}/hdrs/HttpCompat.cc            |    0
 {proxy => src/proxy}/hdrs/HuffmanCodec.cc          |    0
 {proxy => src/proxy}/hdrs/MIME.cc                  |    0
 {proxy => src/proxy}/hdrs/Makefile.am              |    0
 {proxy => src/proxy}/hdrs/URL.cc                   |    0
 {proxy => src/proxy}/hdrs/VersionConverter.cc      |    0
 {proxy => src/proxy}/hdrs/XPACK.cc                 |    0
 {proxy => src/proxy}/hdrs/load_http_hdr.cc         |    0
 {proxy => src/proxy}/hdrs/test_urlhash.cc          |    0
 .../proxy}/hdrs/unit_tests/test_HdrHeap.cc         |    0
 .../proxy}/hdrs/unit_tests/test_HdrUtils.cc        |    0
 {proxy => src/proxy}/hdrs/unit_tests/test_Hdrs.cc  |    0
 .../proxy}/hdrs/unit_tests/test_HeaderValidator.cc |    0
 .../proxy}/hdrs/unit_tests/test_Huffmancode.cc     |    0
 {proxy => src/proxy}/hdrs/unit_tests/test_URL.cc   |    0
 {proxy => src/proxy}/hdrs/unit_tests/test_XPACK.cc |    0
 src/proxy/hdrs/unit_tests/test_mime.cc             |  251 +
 .../proxy}/hdrs/unit_tests/unit_test_main.cc       |    0
 src/proxy/http/CMakeLists.txt                      |   94 +
 {proxy => src/proxy}/http/ConnectingEntry.cc       |    0
 {proxy => src/proxy}/http/ForwardedConfig.cc       |    0
 {proxy => src/proxy}/http/Http1ClientSession.cc    |    0
 .../proxy}/http/Http1ClientTransaction.cc          |    0
 {proxy => src/proxy}/http/Http1ServerSession.cc    |    0
 .../proxy}/http/Http1ServerTransaction.cc          |    0
 src/proxy/http/HttpBodyFactory.cc                  | 1165 +++
 {proxy => src/proxy}/http/HttpCacheSM.cc           |    0
 src/proxy/http/HttpConfig.cc                       | 1498 ++++
 {proxy => src/proxy}/http/HttpConnectionCount.cc   |    0
 src/proxy/http/HttpDebugNames.cc                   |  664 ++
 {proxy => src/proxy}/http/HttpPages.cc             |    0
 {proxy => src/proxy}/http/HttpProxyServerMain.cc   |    0
 src/proxy/http/HttpSM.cc                           | 8797 +++++++++++++++++++
 src/proxy/http/HttpSessionAccept.cc                |   90 +
 {proxy => src/proxy}/http/HttpSessionManager.cc    |    0
 src/proxy/http/HttpTransact.cc                     | 8905 ++++++++++++++++++++
 src/proxy/http/HttpTransactHeaders.cc              | 1306 +++
 {proxy => src/proxy}/http/HttpTunnel.cc            |    0
 src/proxy/http/HttpVCTable.cc                      |  136 +
 {proxy => src/proxy}/http/Makefile.am              |    0
 {proxy => src/proxy}/http/PreWarmConfig.cc         |    0
 src/proxy/http/PreWarmManager.cc                   | 1173 +++
 {proxy => src/proxy}/http/README.via               |    0
 .../proxy}/http/RegressionHttpTransact.cc          |    0
 {proxy => src/proxy}/http/TestUrl.cc               |    0
 {proxy => src/proxy}/http/remap/AclFiltering.cc    |    0
 src/proxy/http/remap/CMakeLists.txt                |   56 +
 {proxy => src/proxy}/http/remap/Makefile.am        |    0
 src/proxy/http/remap/NextHopConsistentHash.cc      |  512 ++
 .../proxy}/http/remap/NextHopHealthStatus.cc       |    0
 .../proxy}/http/remap/NextHopRoundRobin.cc         |    0
 src/proxy/http/remap/NextHopSelectionStrategy.cc   |  424 +
 .../proxy}/http/remap/NextHopStrategyFactory.cc    |    0
 {proxy => src/proxy}/http/remap/PluginDso.cc       |    0
 {proxy => src/proxy}/http/remap/PluginFactory.cc   |    0
 src/proxy/http/remap/RemapConfig.cc                | 1365 +++
 {proxy => src/proxy}/http/remap/RemapHitCount.cc   |    0
 {proxy => src/proxy}/http/remap/RemapPluginInfo.cc |    0
 {proxy => src/proxy}/http/remap/RemapPlugins.cc    |    0
 {proxy => src/proxy}/http/remap/RemapProcessor.cc  |    0
 src/proxy/http/remap/UrlMapping.cc                 |  204 +
 .../proxy}/http/remap/UrlMappingPathIndex.cc       |    0
 src/proxy/http/remap/UrlRewrite.cc                 |  966 +++
 .../proxy}/http/remap/unit-tests/combined.yaml     |    0
 .../remap/unit-tests/consistent-hash-tests.yaml    |    0
 .../proxy}/http/remap/unit-tests/hosts.yaml        |    0
 .../http/remap/unit-tests/nexthop_test_stubs.cc    |  211 +
 .../http/remap/unit-tests/nexthop_test_stubs.h     |    0
 .../proxy}/http/remap/unit-tests/peering.yaml      |    0
 .../http/remap/unit-tests/plugin_init_fail.cc      |    0
 .../http/remap/unit-tests/plugin_instinit_fail.cc  |    0
 .../proxy}/http/remap/unit-tests/plugin_misc_cb.cc |    0
 .../unit-tests/plugin_missing_deleteinstance.cc    |    0
 .../remap/unit-tests/plugin_missing_doremap.cc     |    0
 .../http/remap/unit-tests/plugin_missing_init.cc   |    0
 .../remap/unit-tests/plugin_missing_newinstance.cc |    0
 .../http/remap/unit-tests/plugin_required_cb.cc    |    0
 .../http/remap/unit-tests/plugin_testing_calls.cc  |    0
 .../http/remap/unit-tests/plugin_testing_common.cc |    0
 .../http/remap/unit-tests/plugin_testing_common.h  |    0
 .../http/remap/unit-tests/round-robin-tests.yaml   |    0
 .../http/remap/unit-tests/simple-strategy.yaml     |    0
 .../remap/unit-tests/strategies-dir/01-hosts.yaml  |    0
 .../remap/unit-tests/strategies-dir/02-groups.yaml |    0
 .../unit-tests/strategies-dir/03-strategies.yaml   |    0
 .../proxy}/http/remap/unit-tests/strategy.yaml     |    0
 .../remap/unit-tests/test_NextHopConsistentHash.cc |    0
 .../remap/unit-tests/test_NextHopRoundRobin.cc     |    0
 .../unit-tests/test_NextHopStrategyFactory.cc      |    0
 .../proxy}/http/remap/unit-tests/test_PluginDso.cc |    0
 .../http/remap/unit-tests/test_PluginFactory.cc    | 1429 ++++
 .../http/remap/unit-tests/test_RemapPlugin.cc      |    0
 {proxy => src/proxy}/http/stats.memo               |    0
 {proxy => src/proxy}/http/test_http_client.pl      |    0
 {proxy => src/proxy}/http/test_proxy.pl            |    0
 {proxy => src/proxy}/http/test_socket_close.cc     |    0
 {proxy => src/proxy}/http/testheaders.cc           |    0
 src/proxy/http/unit_tests/CMakeLists.txt           |   50 +
 src/proxy/http/unit_tests/main.cc                  |   60 +
 .../proxy}/http/unit_tests/test_ForwardedConfig.cc |    0
 src/proxy/http/unit_tests/test_HttpTransact.cc     |  590 ++
 src/proxy/http/unit_tests/test_HttpUserAgent.cc    |   93 +
 .../proxy}/http/unit_tests/test_PreWarm.cc         |    0
 .../http/unit_tests/test_error_page_selection.cc   |    0
 src/proxy/http/unit_tests/unit_test_main.cc        |   30 +
 src/proxy/http2/CMakeLists.txt                     |   82 +
 {proxy => src/proxy}/http2/HPACK.cc                |    0
 {proxy => src/proxy}/http2/HTTP2.cc                |    0
 {proxy => src/proxy}/http2/Http2ClientSession.cc   |    0
 {proxy => src/proxy}/http2/Http2CommonSession.cc   |    0
 {proxy => src/proxy}/http2/Http2ConnectionState.cc |    0
 {proxy => src/proxy}/http2/Http2DebugNames.cc      |    0
 {proxy => src/proxy}/http2/Http2Frame.cc           |    0
 .../proxy}/http2/Http2FrequencyCounter.cc          |    0
 {proxy => src/proxy}/http2/Http2ServerSession.cc   |    0
 src/proxy/http2/Http2SessionAccept.cc              |   90 +
 {proxy => src/proxy}/http2/Http2Stream.cc          |    0
 {proxy => src/proxy}/http2/Makefile.am             |    0
 .../proxy}/http2/hpack-tests/story_00.json         |    0
 .../proxy}/http2/hpack-tests/story_01.json         |    0
 .../proxy}/http2/hpack-tests/story_02.json         |    0
 .../proxy}/http2/hpack-tests/story_03.json         |    0
 .../proxy}/http2/hpack-tests/story_04.json         |    0
 .../proxy}/http2/hpack-tests/story_05.json         |    0
 .../proxy}/http2/hpack-tests/story_06.json         |    0
 .../proxy}/http2/hpack-tests/story_07.json         |    0
 .../proxy}/http2/hpack-tests/story_08.json         |    0
 .../proxy}/http2/hpack-tests/story_09.json         |    0
 .../proxy}/http2/hpack-tests/story_10.json         |    0
 .../proxy}/http2/hpack-tests/story_11.json         |    0
 .../proxy}/http2/hpack-tests/story_12.json         |    0
 .../proxy}/http2/hpack-tests/story_13.json         |    0
 .../proxy}/http2/hpack-tests/story_14.json         |    0
 .../proxy}/http2/hpack-tests/story_15.json         |    0
 .../proxy}/http2/hpack-tests/story_16.json         |    0
 .../proxy}/http2/hpack-tests/story_17.json         |    0
 .../proxy}/http2/hpack-tests/story_18.json         |    0
 .../proxy}/http2/hpack-tests/story_19.json         |    0
 .../proxy}/http2/hpack-tests/story_20.json         |    0
 .../proxy}/http2/hpack-tests/story_21.json         |    0
 .../proxy}/http2/hpack-tests/story_22.json         |    0
 .../proxy}/http2/hpack-tests/story_23.json         |    0
 .../proxy}/http2/hpack-tests/story_24.json         |    0
 .../proxy}/http2/hpack-tests/story_25.json         |    0
 .../proxy}/http2/hpack-tests/story_26.json         |    0
 .../proxy}/http2/hpack-tests/story_27.json         |    0
 .../proxy}/http2/hpack-tests/story_28.json         |    0
 .../proxy}/http2/hpack-tests/story_29.json         |    0
 .../proxy}/http2/hpack-tests/story_30.json         |    0
 .../proxy}/http2/hpack-tests/story_31.json         |    0
 src/proxy/http2/test_HPACK.cc                      |  429 +
 src/proxy/http2/unit_tests/main.cc                 |   65 +
 .../proxy}/http2/unit_tests/test_HTTP2.cc          |    0
 .../http2/unit_tests/test_HpackIndexingTable.cc    |    0
 .../http2/unit_tests/test_Http2DependencyTree.cc   |    0
 .../proxy}/http2/unit_tests/test_Http2Frame.cc     |    0
 .../http2/unit_tests/test_Http2FrequencyCounter.cc |    0
 src/proxy/http3/CMakeLists.txt                     |  100 +
 {proxy => src/proxy}/http3/Http09App.cc            |    0
 {proxy => src/proxy}/http3/Http3.cc                |    0
 {proxy => src/proxy}/http3/Http3App.cc             |    0
 {proxy => src/proxy}/http3/Http3Config.cc          |    0
 {proxy => src/proxy}/http3/Http3DataFramer.cc      |    0
 {proxy => src/proxy}/http3/Http3DebugNames.cc      |    0
 {proxy => src/proxy}/http3/Http3Frame.cc           |    0
 {proxy => src/proxy}/http3/Http3FrameCollector.cc  |    0
 {proxy => src/proxy}/http3/Http3FrameDispatcher.cc |    0
 src/proxy/http3/Http3HeaderFramer.cc               |  115 +
 src/proxy/http3/Http3HeaderVIOAdaptor.cc           |  149 +
 .../proxy}/http3/Http3ProtocolEnforcer.cc          |    0
 {proxy => src/proxy}/http3/Http3Session.cc         |    0
 src/proxy/http3/Http3SessionAccept.cc              |  101 +
 {proxy => src/proxy}/http3/Http3SettingsHandler.cc |    0
 src/proxy/http3/Http3StreamDataVIOAdaptor.cc       |   74 +
 {proxy => src/proxy}/http3/Http3Transaction.cc     |    0
 {proxy => src/proxy}/http3/Http3Types.cc           |    0
 {proxy => src/proxy}/http3/Makefile.am             |    0
 {proxy => src/proxy}/http3/QPACK.cc                |    0
 {proxy => src/proxy}/http3/test/Mock.h             |    0
 src/proxy/http3/test/main.cc                       |   62 +
 src/proxy/http3/test/main_qpack.cc                 |  107 +
 {proxy => src/proxy}/http3/test/stub.cc            |    0
 {proxy => src/proxy}/http3/test/test_Http3Frame.cc |    0
 .../proxy}/http3/test/test_Http3FrameDispatcher.cc |    0
 {proxy => src/proxy}/http3/test/test_QPACK.cc      |    0
 src/proxy/logging/CMakeLists.txt                   |   62 +
 src/proxy/logging/Log.cc                           | 1413 ++++
 src/proxy/logging/LogAccess.cc                     | 3297 ++++++++
 {proxy => src/proxy}/logging/LogAccessTest.cc      |    0
 {proxy => src/proxy}/logging/LogAccessTest.h       |    0
 {proxy => src/proxy}/logging/LogBuffer.cc          |    0
 src/proxy/logging/LogConfig.cc                     |  815 ++
 {proxy => src/proxy}/logging/LogField.cc           |    0
 {proxy => src/proxy}/logging/LogFieldAliasMap.cc   |    0
 src/proxy/logging/LogFile.cc                       |  772 ++
 {proxy => src/proxy}/logging/LogFilter.cc          |    0
 {proxy => src/proxy}/logging/LogFormat.cc          |    0
 {proxy => src/proxy}/logging/LogObject.cc          |    0
 src/proxy/logging/LogStandalone.cc                 |  210 +
 {proxy => src/proxy}/logging/LogUtils.cc           |    0
 {proxy => src/proxy}/logging/Makefile.am           |    0
 {proxy => src/proxy}/logging/RolledLogDeleter.cc   |    0
 {proxy => src/proxy}/logging/YamlLogConfig.cc      |    0
 .../proxy}/logging/YamlLogConfigDecoders.cc        |    0
 .../logging/unit-tests/benchmark_LogObject.cc      |  194 +
 .../proxy}/logging/unit-tests/test_LogUtils.cc     |    0
 .../proxy}/logging/unit-tests/test_LogUtils.h      |    0
 .../logging/unit-tests/test_RolledLogDeleter.cc    |    0
 {proxy => src/proxy}/private/Makefile.inc          |    0
 src/proxy/private/SSLProxySession.cc               |   39 +
 {proxy => src/proxy}/private/SSLProxySession.h     |    0
 {proxy => src/proxy}/shared/CMakeLists.txt         |    0
 src/proxy/shared/DiagsConfig.cc                    |  378 +
 {proxy => src/proxy}/shared/Makefile.am            |    0
 src/records/CMakeLists.txt                         |    5 +-
 src/records/RecConfigParse.cc                      |    2 +-
 src/records/RecCore.cc                             |    4 +-
 src/records/RecHttp.cc                             |    4 +-
 src/records/RecMessage.cc                          |    2 +-
 src/records/RecMutex.cc                            |    2 +-
 src/records/RecUtils.cc                            |    2 +-
 src/records/RecYAMLDecoder.cc                      |    2 +-
 src/records/RecordsConfig.cc                       |    2 +-
 src/records/RecordsConfigUtils.cc                  |    2 +-
 src/records/test_I_RecProcess.cc                   |    2 +-
 src/records/test_RecordsConfig.cc                  |    2 +-
 src/records/unit_tests/test_RecHttp.cc             |    2 +-
 .../unit_tests/unit_test_main_on_eventsystem.cc    |    4 +-
 src/tests/CMakeLists.txt                           |   69 +-
 src/traffic_cache_tool/CacheDefs.h                 |    2 +-
 src/traffic_cache_tool/CacheScan.cc                |    8 +-
 src/traffic_cache_tool/CacheScan.h                 |    2 +-
 src/traffic_crashlog/traffic_crashlog.cc           |    8 +-
 src/traffic_ctl/traffic_ctl.cc                     |    2 +-
 src/traffic_layout/engine.cc                       |    6 +-
 src/traffic_layout/info.cc                         |    6 +-
 src/traffic_layout/traffic_layout.cc               |    2 +-
 src/traffic_logcat/CMakeLists.txt                  |    1 +
 src/traffic_logcat/logcat.cc                       |    2 +-
 src/traffic_logstats/CMakeLists.txt                |    1 +
 src/traffic_logstats/logstats.cc                   |    4 +-
 src/traffic_quic/quic_client.h                     |    4 +-
 src/traffic_quic/traffic_quic.cc                   |    6 +-
 src/traffic_server/CMakeLists.txt                  |   14 +-
 src/traffic_server/Crash.cc                        |    6 +-
 src/traffic_server/EventName.cc                    |    6 +-
 src/traffic_server/SocksProxy.cc                   |    2 +-
 src/traffic_server/traffic_server.cc               |    8 +-
 src/traffic_top/traffic_top.cc                     |    4 +-
 src/traffic_via/traffic_via.cc                     |    2 +-
 src/tscore/ArgParser.cc                            |    2 +-
 src/tscore/Layout.cc                               |    2 +-
 src/tscore/Regression.cc                           |    2 +-
 src/tscore/Version.cc                              |    2 +-
 src/tscore/ink_args.cc                             |    2 +-
 src/tscore/runroot.cc                              |    2 +-
 src/tscore/unit_tests/test_Version.cc              |    2 +-
 src/tscore/unit_tests/test_layout.cc               |    2 +-
 tests/fuzzing/CMakeLists.txt                       |   13 +-
 tests/fuzzing/fuzz_rec_http.cc                     |    2 +-
 .../gold_tests/jsonrpc/jsonrpc_api_schema.test.py  |    2 +-
 tests/gold_tests/jsonrpc/plugins/CMakeLists.txt    |    2 +-
 .../jsonrpc/plugins/jsonrpc_plugin_handler_test.cc |    2 +-
 tools/benchmark/benchmark_ProxyAllocator.cc        |    4 +-
 tools/jtest/jtest.cc                               |    2 +-
 1293 files changed, 111842 insertions(+), 111687 deletions(-)

diff --git a/.gitignore b/.gitignore
index d851e8385b..8ed8ac5e6e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -107,43 +107,43 @@ src/records/test_librecords_on_eventsystem
 src/api/test_Metrics
 lib/perl/lib/Apache/TS.pm
 
-iocore/net/test_certlookup
-iocore/net/test_UDPNet
-iocore/net/test_libinknet
-iocore/net/quic/test_*
-iocore/aio/test_AIO
-iocore/eventsystem/test_IOBuffer
-iocore/eventsystem/test_EventSystem
-iocore/eventsystem/test_MIOBufferWriter
-
-iocore/hostdb/test_RefCountCache
-iocore/hostdb/test_HostFile
-
-proxy/hdrs/test_mime
-proxy/hdrs/test_Huffmancode
-proxy/hdrs/test_proxy_hdrs
-proxy/hdrs/test_hdr_heap
-proxy/hdrs/test_Huffmancode
-proxy/hdrs/test_XPACK
-proxy/http/test_HttpTransact
-proxy/http/remap/test_NextHopRoundRobin
-proxy/http/remap/test_NextHopStrategyFactory
-proxy/http/remap/test_PluginDso
-proxy/http/remap/test_PluginFactory
-proxy/http/remap/test_RemapPluginInfo
-proxy/http/test_proxy_http
-proxy/http/test_PreWarm
-proxy/http/remap/test_*
-proxy/http2/test_libhttp2
-proxy/http2/test_Http2DependencyTree
-proxy/http2/test_Http2FrequencyCounter
-proxy/http2/test_HPACK
-proxy/http2/hpack-tests/results
-proxy/http3/test_libhttp3
-proxy/http3/test_qpack
-proxy/logging/test_LogUtils
-proxy/logging/test_LogUtils2
-proxy/logging/test_RolledLogDeleter
+src/iocore/net/test_certlookup
+src/iocore/net/test_UDPNet
+src/iocore/net/test_libinknet
+src/iocore/net/quic/test_*
+src/iocore/aio/test_AIO
+src/iocore/eventsystem/test_IOBuffer
+src/iocore/eventsystem/test_EventSystem
+src/iocore/eventsystem/test_MIOBufferWriter
+
+src/iocore/hostdb/test_RefCountCache
+src/iocore/hostdb/test_HostFile
+
+src/proxy/hdrs/test_mime
+src/proxy/hdrs/test_Huffmancode
+src/proxy/hdrs/test_proxy_hdrs
+src/proxy/hdrs/test_hdr_heap
+src/proxy/hdrs/test_Huffmancode
+src/proxy/hdrs/test_XPACK
+src/proxy/http/test_HttpTransact
+src/proxy/http/remap/test_NextHopRoundRobin
+src/proxy/http/remap/test_NextHopStrategyFactory
+src/proxy/http/remap/test_PluginDso
+src/proxy/http/remap/test_PluginFactory
+src/proxy/http/remap/test_RemapPluginInfo
+src/proxy/http/test_proxy_http
+src/proxy/http/test_PreWarm
+src/proxy/http/remap/test_*
+src/proxy/http2/test_libhttp2
+src/proxy/http2/test_Http2DependencyTree
+src/proxy/http2/test_Http2FrequencyCounter
+src/proxy/http2/test_HPACK
+src/proxy/http2/hpack-tests/results
+src/proxy/http3/test_libhttp3
+src/proxy/http3/test_qpack
+src/proxy/logging/test_LogUtils
+src/proxy/logging/test_LogUtils2
+src/proxy/logging/test_RolledLogDeleter
 
 plugins/authproxy/authproxy_test
 plugins/esi/*_test
@@ -162,17 +162,10 @@ tools/benchmark/benchmark_FreeList
 tools/benchmark/benchmark_ProxyAllocator
 tools/benchmark/benchmark_SharedMutex
 
-mgmt/rpc/overridable_txn_vars.cc
-mgmt/rpc/IPCSocketClient.cc
-mgmt/rpc/test_jsonrpc
-mgmt/rpc/test_jsonrpcserver
-mgmt/tools/traffic_mcast_snoop
-mgmt/tools/traffic_net_config
-mgmt/tools/traffic_shmem_clean
-mgmt/tools/traffic_time_config
-mgmt/tools/traffic_vip_config
-mgmt/tools/shmem_clean
-mgmt/utils/test_mgmt_utils
+src/mgmt/rpc/overridable_txn_vars.cc
+src/mgmt/rpc/IPCSocketClient.cc
+src/mgmt/rpc/test_jsonrpc
+src/mgmt/rpc/test_jsonrpcserver
 
 libtool
 m4/libtool.m4
@@ -228,5 +221,5 @@ tests/gold_tests/bigobj/push_request
 tests/gold_tests/chunked_encoding/smuggle-client
 tests/gold_tests/tls/ssl-post
 
-iocore/cache/test_*
-iocore/cache/test/var/trafficserver/cache.db
+src/iocore/cache/test_*
+src/iocore/cache/test/var/trafficserver/cache.db
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 2b88568d8d..64b1bd45db 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -572,10 +572,10 @@ add_subdirectory(src/tscpp/util)
 add_subdirectory(src/tscpp/api)
 add_subdirectory(src/tscore)
 add_subdirectory(src/records)
-add_subdirectory(iocore)
-add_subdirectory(proxy)
-add_subdirectory(mgmt/config)
-add_subdirectory(mgmt/rpc)
+add_subdirectory(src/iocore)
+add_subdirectory(src/proxy)
+add_subdirectory(src/mgmt/config)
+add_subdirectory(src/mgmt/rpc)
 add_subdirectory(src/api)
 add_subdirectory(src/traffic_crashlog)
 add_subdirectory(src/traffic_server)
@@ -647,11 +647,8 @@ endfunction(add_clang_format_target)
 
 add_clang_format_target(src)
 add_clang_format_target(example)
-add_clang_format_target(iocore)
 add_clang_format_target(include)
-add_clang_format_target(mgmt)
 add_clang_format_target(plugins)
-add_clang_format_target(proxy)
 add_clang_format_target(tools)
 add_clang_format_target(tests)
 
diff --git a/ci/jenkins/bin/autest.sh b/ci/jenkins/bin/autest.sh
index 995b472ea8..455379f2cc 100755
--- a/ci/jenkins/bin/autest.sh
+++ b/ci/jenkins/bin/autest.sh
@@ -23,7 +23,7 @@ sleep 30
 
 git branch --contains ${ghprbActualCommit} > /dev/null
 if [ $? = 0 -a ! -z "$ghprbActualCommit" ]; then
-    git diff HEAD~1 --name-only | egrep -E '^(build|iocore|proxy|tests|include|mgmt|plugins|proxy|src)/' > /dev/null
+    git diff HEAD~1 --name-only | egrep -E '^(build|tests|include|plugins|src)/' > /dev/null
     if [ $? = 1 ]; then
         echo "No relevant files changed, skipping run"
         exit 0
diff --git a/contrib/python/compare_RecordsConfigcc.py b/contrib/python/compare_RecordsConfigcc.py
index 2eebce3096..8fc3a852a4 100755
--- a/contrib/python/compare_RecordsConfigcc.py
+++ b/contrib/python/compare_RecordsConfigcc.py
@@ -45,7 +45,7 @@ rc_in = {}  # records.config.in values
 rc_doc = {}  # documented values
 
 # Process RecordsConfig.cc
-with open(f"{src_dir}/mgmt/RecordsConfig.cc") as fh:
+with open(f"{src_dir}/src/mgmt/RecordsConfig.cc") as fh:
     cc_re = re.compile(r'\{RECT_(?:CONFIG|LOCAL), "([^"]+)", RECD_([A-Z]+), (.+?), ')
     for line in fh:
         m = cc_re.search(line)
diff --git a/doc/Doxyfile b/doc/Doxyfile
index 4cde23176a..b8022942e6 100644
--- a/doc/Doxyfile
+++ b/doc/Doxyfile
@@ -747,10 +747,7 @@ WARN_LOGFILE           =
 
 INPUT                  = mainpage.doc \
                          ../include \
-                         ../iocore \
                          ../src/records \
-                         ../mgmt \
-                         ../proxy \
                          ../src
 
 # This tag can be used to specify the character encoding of the source files
diff --git a/include/api/InkAPIInternal.h b/include/api/InkAPIInternal.h
index 4d2f31695d..086bcffd84 100644
--- a/include/api/InkAPIInternal.h
+++ b/include/api/InkAPIInternal.h
@@ -23,14 +23,14 @@
 
 #pragma once
 
-#include "I_EventSystem.h"
+#include "EventSystem.h"
 #include "URL.h"
-#include "I_Net.h"
+#include "Net.h"
 #include "HTTP.h"
 #include "tscore/List.h"
 #include "ConfigProcessor.h"
-#include "I_Cache.h"
-#include "I_Tasks.h"
+#include "Cache.h"
+#include "Tasks.h"
 #include "Plugin.h"
 
 #include "api/APIHook.h"
diff --git a/include/iocore/aio/AIO.h b/include/iocore/aio/AIO.h
new file mode 100644
index 0000000000..6d793a5ffa
--- /dev/null
+++ b/include/iocore/aio/AIO.h
@@ -0,0 +1,85 @@
+/** @file
+
+  A brief file description
+
+  @section license License
+
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ */
+
+/****************************************************************************
+
+  Async Disk IO operations.
+
+
+
+ ****************************************************************************/
+#pragma once
+
+#include "tscore/ink_platform.h"
+#include "EventSystem.h"
+#include "records/RecProcess.h"
+
+static constexpr ts::ModuleVersion AIO_MODULE_PUBLIC_VERSION(1, 0, ts::ModuleVersion::PUBLIC);
+
+#define AIO_EVENT_DONE (AIO_EVENT_EVENTS_START + 0)
+
+#define LIO_READ  0x1
+#define LIO_WRITE 0x2
+
+enum AIOBackend {
+  AIO_BACKEND_AUTO     = 0,
+  AIO_BACKEND_THREAD   = 1,
+  AIO_BACKEND_IO_URING = 2,
+};
+
+struct ink_aiocb {
+  int aio_fildes    = -1;      /* file descriptor or status: AIO_NOT_IN_PROGRESS */
+  void *aio_buf     = nullptr; /* buffer location */
+  size_t aio_nbytes = 0;       /* length of transfer */
+  off_t aio_offset  = 0;       /* file offset */
+
+  int aio_lio_opcode = 0; /* listio operation */
+  int aio_state      = 0; /* state flag for List I/O */
+};
+
+bool ink_aio_thread_num_set(int thread_num);
+
+// AIOCallback::thread special values
+#define AIO_CALLBACK_THREAD_ANY ((EThread *)0) // any regular event thread
+#define AIO_CALLBACK_THREAD_AIO ((EThread *)-1)
+
+struct AIOCallback : public Continuation {
+  // set before calling aio_read/aio_write
+  ink_aiocb aiocb;
+  Action action;
+  EThread *thread   = AIO_CALLBACK_THREAD_ANY;
+  AIOCallback *then = nullptr;
+  // set on return from aio_read/aio_write
+  int64_t aio_result = 0;
+
+  int ok();
+  AIOCallback() {}
+};
+
+void ink_aio_init(ts::ModuleVersion version, AIOBackend backend = AIO_BACKEND_AUTO);
+void ink_aio_set_err_callback(Continuation *error_callback);
+
+int ink_aio_read(AIOCallback *op,
+                 int fromAPI = 0); // fromAPI is a boolean to indicate if this is from an API call such as upload proxy feature
+int ink_aio_write(AIOCallback *op, int fromAPI = 0);
+AIOCallback *new_AIOCallback();
diff --git a/include/iocore/aio/AIO_fault_injection.h b/include/iocore/aio/AIO_fault_injection.h
new file mode 100644
index 0000000000..c95693a524
--- /dev/null
+++ b/include/iocore/aio/AIO_fault_injection.h
@@ -0,0 +1,72 @@
+/** @file
+
+  A mechanism to simulate disk failure by injecting faults in userspace.
+
+  @section license License
+
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ */
+
+#pragma once
+
+#include "Continuation.h"
+#include "Lock.h"
+#include "tscore/ink_assert.h"
+#include "tscore/ink_mutex.h"
+#include <cerrno>
+#include <fcntl.h>
+#include <filesystem>
+#include <regex>
+#include <unistd.h>
+#include <unordered_map>
+#include <vector>
+
+// We need a way to simulate failures determininstically to test disk
+// initialization
+
+static constexpr auto TAG{"fault"};
+
+class AIOFaultInjection
+{
+  struct IOFault {
+    int err_no;
+    bool skip_io;
+  };
+  using IOFaults = std::unordered_map<int, IOFault>;
+
+  struct IOFaultState {
+    std::size_t op_count = 0;
+  };
+
+  std::unordered_map<std::string, IOFaults> _faults_by_regex;
+  std::unordered_map<int, IOFaults &> _faults_by_fd;
+  std::unordered_map<int, IOFaultState> _state_by_fd;
+
+  void _decrement_op_count(int fd);
+  IOFault _op_result(int fd);
+
+  std::mutex _mutex;
+
+public:
+  void inject_fault(const char *path_regex, int op_index, IOFault fault);
+
+  int open(const char *pathname, int flags, mode_t mode);
+  ssize_t pread(int fd, void *buf, size_t nbytes, off_t offset);
+  ssize_t pwrite(int fd, const void *buf, size_t n, off_t offset);
+};
+
+extern AIOFaultInjection aioFaultInjection;
diff --git a/include/iocore/cache/Cache.h b/include/iocore/cache/Cache.h
new file mode 100644
index 0000000000..faaacc1475
--- /dev/null
+++ b/include/iocore/cache/Cache.h
@@ -0,0 +1,223 @@
+/** @file
+
+  A brief file description
+
+  @section license License
+
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ */
+
+#pragma once
+
+#include "tscore/ink_platform.h"
+#include "EventSystem.h"
+#include "AIO.h"
+#include "CacheDefs.h"
+#include "Store.h"
+
+static constexpr ts::ModuleVersion CACHE_MODULE_VERSION(1, 0);
+
+#define CACHE_WRITE_OPT_OVERWRITE      0x0001
+#define CACHE_WRITE_OPT_CLOSE_COMPLETE 0x0002
+#define CACHE_WRITE_OPT_SYNC           (CACHE_WRITE_OPT_CLOSE_COMPLETE | 0x0004)
+#define CACHE_WRITE_OPT_OVERWRITE_SYNC (CACHE_WRITE_OPT_SYNC | CACHE_WRITE_OPT_OVERWRITE)
+
+#define SCAN_KB_PER_SECOND 8192 // 1TB/8MB = 131072 = 36 HOURS to scan a TB
+
+#define RAM_CACHE_ALGORITHM_CLFUS 0
+#define RAM_CACHE_ALGORITHM_LRU   1
+
+#define CACHE_COMPRESSION_NONE    0
+#define CACHE_COMPRESSION_FASTLZ  1
+#define CACHE_COMPRESSION_LIBZ    2
+#define CACHE_COMPRESSION_LIBLZMA 3
+
+enum { RAM_HIT_COMPRESS_NONE = 1, RAM_HIT_COMPRESS_FASTLZ, RAM_HIT_COMPRESS_LIBZ, RAM_HIT_COMPRESS_LIBLZMA, RAM_HIT_LAST_ENTRY };
+
+struct CacheVC;
+class CacheEvacuateDocVC;
+struct CacheDisk;
+struct OverridableHttpConfigParams;
+class URL;
+class HTTPHdr;
+class HTTPInfo;
+
+using CacheHTTPHdr  = HTTPHdr;
+using CacheURL      = URL;
+using CacheHTTPInfo = HTTPInfo;
+
+struct CacheProcessor : public Processor {
+  CacheProcessor()
+    : min_stripe_version(CACHE_DB_MAJOR_VERSION, CACHE_DB_MINOR_VERSION),
+      max_stripe_version(CACHE_DB_MAJOR_VERSION, CACHE_DB_MINOR_VERSION)
+
+  {
+  }
+
+  int start(int n_cache_threads = 0, size_t stacksize = DEFAULT_STACKSIZE) override;
+  virtual int start_internal(int flags = 0);
+  void stop();
+
+  int dir_check(bool fix);
+
+  Action *lookup(Continuation *cont, const CacheKey *key, CacheFragType frag_type = CACHE_FRAG_TYPE_NONE,
+                 const char *hostname = nullptr, int host_len = 0);
+  Action *open_read(Continuation *cont, const CacheKey *key, CacheFragType frag_type = CACHE_FRAG_TYPE_NONE,
+                    const char *hostname = nullptr, int host_len = 0);
+  Action *open_write(Continuation *cont, CacheKey *key, CacheFragType frag_type = CACHE_FRAG_TYPE_NONE,
+                     int expected_size = CACHE_EXPECTED_SIZE, int options = 0, time_t pin_in_cache = (time_t)0,
+                     char *hostname = nullptr, int host_len = 0);
+  Action *remove(Continuation *cont, const CacheKey *key, CacheFragType frag_type = CACHE_FRAG_TYPE_NONE,
+                 const char *hostname = nullptr, int host_len = 0);
+  Action *scan(Continuation *cont, char *hostname = nullptr, int host_len = 0, int KB_per_second = SCAN_KB_PER_SECOND);
+  Action *lookup(Continuation *cont, const HttpCacheKey *key, CacheFragType frag_type = CACHE_FRAG_TYPE_HTTP);
+  Action *open_read(Continuation *cont, const HttpCacheKey *key, CacheHTTPHdr *request, const OverridableHttpConfigParams *params,
+                    time_t pin_in_cache = (time_t)0, CacheFragType frag_type = CACHE_FRAG_TYPE_HTTP);
+  Action *open_write(Continuation *cont, int expected_size, const HttpCacheKey *key, CacheHTTPHdr *request, CacheHTTPInfo *old_info,
+                     time_t pin_in_cache = (time_t)0, CacheFragType frag_type = CACHE_FRAG_TYPE_HTTP);
+  Action *remove(Continuation *cont, const HttpCacheKey *key, CacheFragType frag_type = CACHE_FRAG_TYPE_HTTP);
+  Action *link(Continuation *cont, CacheKey *from, CacheKey *to, CacheFragType frag_type = CACHE_FRAG_TYPE_HTTP,
+               char *hostname = nullptr, int host_len = 0);
+
+  Action *deref(Continuation *cont, CacheKey *key, CacheFragType frag_type = CACHE_FRAG_TYPE_HTTP, char *hostname = nullptr,
+                int host_len = 0);
+
+  /** Mark physical disk/device/file as offline.
+      All stripes for this device are disabled.
+
+      @return @c true if there are any storage devices remaining online, @c false if not.
+
+      @note This is what is called if a disk is disabled due to I/O errors.
+  */
+  bool mark_storage_offline(CacheDisk *d, bool admin = false);
+
+  /** Find the storage for a @a path.
+      If @a len is 0 then @a path is presumed null terminated.
+      @return @c nullptr if the path does not match any defined storage.
+   */
+  CacheDisk *find_by_path(const char *path, int len = 0);
+
+  /** Check if there are any online storage devices.
+      If this returns @c false then the cache should be disabled as there is no storage available.
+  */
+  bool has_online_storage() const;
+
+  static int IsCacheEnabled();
+
+  static bool IsCacheReady(CacheFragType type);
+
+  /// Type for callback function.
+  using CALLBACK_FUNC = void (*)();
+  /** Lifecycle callback.
+
+      The function @a cb is called after cache initialization has
+      finished and the cache is ready or has failed.
+
+      @internal If we need more lifecycle callbacks, this should be
+      generalized ala the standard hooks style, with a type enum used
+      to specific the callback type and passed to the callback
+      function.
+  */
+  void afterInitCallbackSet(CALLBACK_FUNC cb);
+
+  // private members
+  void diskInitialized();
+
+  void cacheInitialized();
+
+  int
+  waitForCache() const
+  {
+    return wait_for_cache;
+  }
+
+  static uint32_t cache_ready;
+  static int initialized;
+  static int start_done;
+  static bool clear;
+  static bool fix;
+  static bool check;
+  static int start_internal_flags;
+  static int auto_clear_flag;
+
+  ts::VersionNumber min_stripe_version;
+  ts::VersionNumber max_stripe_version;
+
+  CALLBACK_FUNC cb_after_init = nullptr;
+  int wait_for_cache          = 0;
+};
+
+inline void
+CacheProcessor::afterInitCallbackSet(CALLBACK_FUNC cb)
+{
+  cb_after_init = cb;
+}
+
+struct CacheVConnection : public VConnection {
+  VIO *do_io_read(Continuation *c, int64_t nbytes, MIOBuffer *buf) override                           = 0;
+  virtual VIO *do_io_pread(Continuation *c, int64_t nbytes, MIOBuffer *buf, int64_t offset)           = 0;
+  VIO *do_io_write(Continuation *c, int64_t nbytes, IOBufferReader *buf, bool owner = false) override = 0;
+  void do_io_close(int lerrno = -1) override                                                          = 0;
+  void reenable(VIO *avio) override                                                                   = 0;
+  void reenable_re(VIO *avio) override                                                                = 0;
+  void
+  do_io_shutdown(ShutdownHowTo_t howto) override
+  {
+    (void)howto;
+    ink_assert(!"CacheVConnection::do_io_shutdown unsupported");
+  }
+
+  virtual int get_header(void **ptr, int *len)      = 0;
+  virtual int set_header(void *ptr, int len)        = 0;
+  virtual int get_single_data(void **ptr, int *len) = 0;
+
+  virtual void set_http_info(CacheHTTPInfo *info)  = 0;
+  virtual void get_http_info(CacheHTTPInfo **info) = 0;
+
+  virtual bool is_ram_cache_hit() const   = 0;
+  virtual bool set_pin_in_cache(time_t t) = 0;
+  virtual time_t get_pin_in_cache()       = 0;
+  virtual int64_t get_object_size()       = 0;
+  virtual bool
+  is_compressed_in_ram() const
+  {
+    return false;
+  }
+
+  virtual int
+  get_volume_number() const
+  {
+    return -1;
+  }
+
+  virtual const char *
+  get_disk_path() const
+  {
+    return nullptr;
+  }
+
+  /** Test if the VC can support pread.
+      @return @c true if @c do_io_pread will work, @c false if not.
+  */
+  virtual bool is_pread_capable() = 0;
+
+  CacheVConnection();
+};
+
+void ink_cache_init(ts::ModuleVersion version);
+extern CacheProcessor cacheProcessor;
+extern Continuation *cacheRegexDeleteCont;
diff --git a/include/iocore/cache/CacheDefs.h b/include/iocore/cache/CacheDefs.h
new file mode 100644
index 0000000000..6cfded4f40
--- /dev/null
+++ b/include/iocore/cache/CacheDefs.h
@@ -0,0 +1,143 @@
+/** @file
+
+  A brief file description
+
+  @section license License
+
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ */
+
+#pragma once
+
+#include "Event.h"
+#include "VConnection.h"
+#include "tscore/Version.h"
+#include "tscore/CryptoHash.h"
+
+#define CACHE_INIT_FAILED  -1
+#define CACHE_INITIALIZING 0
+#define CACHE_INITIALIZED  1
+
+#define CACHE_ALT_INDEX_DEFAULT -1
+#define CACHE_ALT_REMOVED       -2
+
+static const uint8_t CACHE_DB_MAJOR_VERSION = 24;
+static const uint8_t CACHE_DB_MINOR_VERSION = 2;
+// This is used in various comparisons because otherwise if the minor version is 0,
+// the compile fails because the condition is always true or false. Running it through
+// VersionNumber prevents that.
+extern const ts::VersionNumber CACHE_DB_VERSION;
+
+static const uint8_t CACHE_DIR_MAJOR_VERSION = 18;
+static const uint8_t CACHE_DIR_MINOR_VERSION = 0;
+
+#define CACHE_DB_FDS 128
+
+// opcodes
+#define CACHE_OPEN_READ              1
+#define CACHE_OPEN_READ_BUFFER       2
+#define CACHE_OPEN_READ_LONG         3
+#define CACHE_OPEN_READ_BUFFER_LONG  4
+#define CACHE_OPEN_WRITE             5
+#define CACHE_OPEN_WRITE_BUFFER      6
+#define CACHE_OPEN_WRITE_LONG        7
+#define CACHE_OPEN_WRITE_BUFFER_LONG 8
+#define CACHE_UPDATE                 9
+#define CACHE_REMOVE                 10
+#define CACHE_LINK                   11
+#define CACHE_DEREF                  12
+#define CACHE_LOOKUP_OP              13
+
+enum CacheType {
+  CACHE_NONE_TYPE = 0, // for empty disk fragments
+  CACHE_HTTP_TYPE = 1,
+  CACHE_RTSP_TYPE = 2
+};
+
+// NOTE: All the failures are ODD, and one greater than the success
+//       Some of these must match those in <ts/ts.h>
+enum CacheEventType {
+  CACHE_EVENT_LOOKUP           = CACHE_EVENT_EVENTS_START + 0,
+  CACHE_EVENT_LOOKUP_FAILED    = CACHE_EVENT_EVENTS_START + 1,
+  CACHE_EVENT_OPEN_READ        = CACHE_EVENT_EVENTS_START + 2,
+  CACHE_EVENT_OPEN_READ_FAILED = CACHE_EVENT_EVENTS_START + 3,
+  // 4-7 unused
+  CACHE_EVENT_OPEN_WRITE        = CACHE_EVENT_EVENTS_START + 8,
+  CACHE_EVENT_OPEN_WRITE_FAILED = CACHE_EVENT_EVENTS_START + 9,
+  CACHE_EVENT_REMOVE            = CACHE_EVENT_EVENTS_START + 12,
+  CACHE_EVENT_REMOVE_FAILED     = CACHE_EVENT_EVENTS_START + 13,
+  CACHE_EVENT_UPDATE,
+  CACHE_EVENT_UPDATE_FAILED,
+  CACHE_EVENT_LINK,
+  CACHE_EVENT_LINK_FAILED,
+  CACHE_EVENT_DEREF,
+  CACHE_EVENT_DEREF_FAILED,
+  CACHE_EVENT_SCAN                   = CACHE_EVENT_EVENTS_START + 20,
+  CACHE_EVENT_SCAN_FAILED            = CACHE_EVENT_EVENTS_START + 21,
+  CACHE_EVENT_SCAN_OBJECT            = CACHE_EVENT_EVENTS_START + 22,
+  CACHE_EVENT_SCAN_OPERATION_BLOCKED = CACHE_EVENT_EVENTS_START + 23,
+  CACHE_EVENT_SCAN_OPERATION_FAILED  = CACHE_EVENT_EVENTS_START + 24,
+  CACHE_EVENT_SCAN_DONE              = CACHE_EVENT_EVENTS_START + 25,
+  //////////////////////////
+  // Internal error codes //
+  //////////////////////////
+  CACHE_EVENT_RESPONSE = CACHE_EVENT_EVENTS_START + 50,
+  CACHE_EVENT_RESPONSE_MSG,
+  CACHE_EVENT_RESPONSE_RETRY
+};
+
+enum CacheScanResult {
+  CACHE_SCAN_RESULT_CONTINUE = EVENT_CONT,
+  CACHE_SCAN_RESULT_DONE     = EVENT_DONE,
+  CACHE_SCAN_RESULT_DELETE   = 10,
+  CACHE_SCAN_RESULT_DELETE_ALL_ALTERNATES,
+  CACHE_SCAN_RESULT_UPDATE,
+  CACHE_SCAN_RESULT_RETRY
+};
+
+enum CacheDataType {
+  CACHE_DATA_HTTP_INFO = VCONNECTION_CACHE_DATA_BASE,
+  CACHE_DATA_KEY,
+  CACHE_DATA_RAM_CACHE_HIT_FLAG,
+};
+
+enum CacheFragType {
+  CACHE_FRAG_TYPE_NONE     = 0,
+  CACHE_FRAG_TYPE_UNUSED_1 = 1, //. Because of the history we need to occupy a space
+  CACHE_FRAG_TYPE_RTSP     = 2, ///< Should be removed once Cache Toolkit is implemented.
+  CACHE_FRAG_TYPE_HTTP     = 3,
+  NUM_CACHE_FRAG_TYPES     = 4
+};
+
+using CacheKey = CryptoHash;
+
+struct HttpCacheKey {
+  int hostlen;
+  const char *hostname;
+  CacheKey hash;
+  CacheKey hash2;
+};
+
+#define CACHE_ALLOW_MULTIPLE_WRITES 1
+#define CACHE_EXPECTED_SIZE         32768
+
+/* uses of the CacheKey
+   word(0) - cache partition segment
+   word(1) - cache partition bucket
+   word(2) - tag (lower bits), hosttable hash (upper bits)
+   word(3) - ram cache hash, lookaside cache
+ */
diff --git a/include/iocore/cache/CacheEvacuateDocVC.h b/include/iocore/cache/CacheEvacuateDocVC.h
new file mode 100644
index 0000000000..13cbc99cd9
--- /dev/null
+++ b/include/iocore/cache/CacheEvacuateDocVC.h
@@ -0,0 +1,72 @@
+/** @file
+
+  A brief file description
+
+  @section license License
+
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ */
+
+#pragma once
+
+/*
+#include "P_CacheDir.h"
+*/
+
+#include "CacheVC.h"
+
+// eventsystem
+#include "Continuation.h"
+#include "EThread.h"
+#include "Event.h"
+#include "ProxyAllocator.h"
+
+// tscore
+#include "tscore/ink_assert.h"
+
+// ts
+#include "ts/DbgCtl.h"
+
+class CacheEvacuateDocVC : public CacheVC
+{
+public:
+  int evacuateDocDone(int /* event ATS_UNUSED */, Event * /* e ATS_UNUSED */);
+  int evacuateReadHead(int /* event ATS_UNUSED */, Event * /* e ATS_UNUSED */);
+};
+
+extern ClassAllocator<CacheEvacuateDocVC> cacheEvacuateDocVConnectionAllocator;
+
+inline CacheEvacuateDocVC *
+new_CacheEvacuateDocVC(Continuation *cont)
+{
+  EThread *t            = cont->mutex->thread_holding;
+  CacheEvacuateDocVC *c = THREAD_ALLOC(cacheEvacuateDocVConnectionAllocator, t);
+  c->vector.data.data   = &c->vector.data.fast_data[0];
+  c->_action            = cont;
+  c->mutex              = cont->mutex;
+  c->start_time         = ink_get_hrtime();
+  c->setThreadAffinity(t);
+  ink_assert(c->trigger == nullptr);
+  static DbgCtl dbg_ctl{"cache_new"};
+  Dbg(dbg_ctl, "new %p", c);
+#ifdef CACHE_STAT_PAGES
+  ink_assert(!c->stat_link.next);
+  ink_assert(!c->stat_link.prev);
+#endif
+  dir_clear(&c->dir);
+  return c;
+}
diff --git a/include/iocore/cache/CacheVC.h b/include/iocore/cache/CacheVC.h
new file mode 100644
index 0000000000..fc9fd60a5f
--- /dev/null
+++ b/include/iocore/cache/CacheVC.h
@@ -0,0 +1,335 @@
+/** @file
+
+  A brief file description
+
+  @section license License
+
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ */
+
+#pragma once
+
+/*
+// inkcache
+#include "Cache.h"
+#include "P_CacheDir.h"
+#include "P_CacheVol.h"
+*/
+#include "P_CacheHttp.h"
+
+// aio
+#include "AIO.h"
+
+// inkevent
+#include "Action.h"
+#include "Continuation.h"
+#include "Event.h"
+#include "IOBuffer.h"
+#include "VIO.h"
+
+// tscore
+#include "tscore/ink_hrtime.h"
+#include "tscore/List.h"
+#include "tscore/Ptr.h"
+
+#include <cstdint>
+
+struct Vol;
+
+struct CacheVC : public CacheVConnection {
+  CacheVC();
+
+  VIO *do_io_read(Continuation *c, int64_t nbytes, MIOBuffer *buf) override;
+  VIO *do_io_pread(Continuation *c, int64_t nbytes, MIOBuffer *buf, int64_t offset) override;
+  VIO *do_io_write(Continuation *c, int64_t nbytes, IOBufferReader *buf, bool owner = false) override;
+  void do_io_close(int lerrno = -1) override;
+  void reenable(VIO *avio) override;
+  void reenable_re(VIO *avio) override;
+  bool get_data(int i, void *data) override;
+  bool set_data(int i, void *data) override;
+
+  bool
+  is_ram_cache_hit() const override
+  {
+    ink_assert(vio.op == VIO::READ);
+    return !f.not_from_ram_cache;
+  }
+
+  int
+  get_header(void **ptr, int *len) override
+  {
+    if (first_buf) {
+      Doc *doc = (Doc *)first_buf->data();
+      *ptr     = doc->hdr();
+      *len     = doc->hlen;
+      return 0;
+    }
+
+    return -1;
+  }
+
+  int
+  set_header(void *ptr, int len) override
+  {
+    header_to_write     = ptr;
+    header_to_write_len = len;
+    return 0;
+  }
+
+  int
+  get_single_data(void **ptr, int *len) override
+  {
+    if (first_buf) {
+      Doc *doc = (Doc *)first_buf->data();
+      if (doc->data_len() == doc->total_len) {
+        *ptr = doc->data();
+        *len = doc->data_len();
+        return 0;
+      }
+    }
+
+    return -1;
+  }
+
+  int
+  get_volume_number() const override
+  {
+    if (vol && vol->cache_vol) {
+      return vol->cache_vol->vol_number;
+    }
+
+    return -1;
+  }
+
+  const char *
+  get_disk_path() const override
+  {
+    if (vol && vol->disk) {
+      return vol->disk->path;
+    }
+
+    return nullptr;
+  }
+
+  bool
+  is_compressed_in_ram() const override
+  {
+    ink_assert(vio.op == VIO::READ);
+    return f.compressed_in_ram;
+  }
+
+  bool writer_done();
+  int calluser(int event);
+  int callcont(int event);
+  int die();
+  int dead(int event, Event *e);
+
+  int handleReadDone(int event, Event *e);
+  int handleRead(int event, Event *e);
+  int do_read_call(CacheKey *akey);
+  int handleWrite(int event, Event *e);
+  int handleWriteLock(int event, Event *e);
+  int do_write_call();
+  int do_write_lock();
+  int do_write_lock_call();
+  int do_sync(uint32_t target_write_serial);
+
+  int openReadClose(int event, Event *e);
+  int openReadReadDone(int event, Event *e);
+  int openReadMain(int event, Event *e);
+  int openReadStartEarliest(int event, Event *e);
+  int openReadVecWrite(int event, Event *e);
+  int openReadStartHead(int event, Event *e);
+  int openReadFromWriter(int event, Event *e);
+  int openReadFromWriterMain(int event, Event *e);
+  int openReadFromWriterFailure(int event, Event *);
+  int openReadChooseWriter(int event, Event *e);
+  int openReadDirDelete(int event, Event *e);
+
+  int openWriteCloseDir(int event, Event *e);
+  int openWriteCloseHeadDone(int event, Event *e);
+  int openWriteCloseHead(int event, Event *e);
+  int openWriteCloseDataDone(int event, Event *e);
+  int openWriteClose(int event, Event *e);
+  int openWriteRemoveVector(int event, Event *e);
+  int openWriteWriteDone(int event, Event *e);
+  int openWriteOverwrite(int event, Event *e);
+  int openWriteMain(int event, Event *e);
+  int openWriteStartDone(int event, Event *e);
+  int openWriteStartBegin(int event, Event *e);
+
+  int updateVector(int event, Event *e);
+  int updateReadDone(int event, Event *e);
+  int updateVecWrite(int event, Event *e);
+
+  int removeEvent(int event, Event *e);
+
+  int scanVol(int event, Event *e);
+  int scanObject(int event, Event *e);
+  int scanUpdateDone(int event, Event *e);
+  int scanOpenWrite(int event, Event *e);
+  int scanRemoveDone(int event, Event *e);
+
+  int
+  is_io_in_progress()
+  {
+    return io.aiocb.aio_fildes != AIO_NOT_IN_PROGRESS;
+  }
+  void
+  set_io_not_in_progress()
+  {
+    io.aiocb.aio_fildes = AIO_NOT_IN_PROGRESS;
+  }
+  void
+  set_agg_write_in_progress()
+  {
+    io.aiocb.aio_fildes = AIO_AGG_WRITE_IN_PROGRESS;
+  }
+
+  void cancel_trigger();
+  int64_t get_object_size() override;
+  void set_http_info(CacheHTTPInfo *info) override;
+  void get_http_info(CacheHTTPInfo **info) override;
+  /** Get the fragment table.
+      @return The address of the start of the fragment table,
+      or @c nullptr if there is no fragment table.
+  */
+  virtual HTTPInfo::FragOffset *get_frag_table();
+  /** Load alt pointers and do fixups if needed.
+      @return Length of header data used for alternates.
+   */
+  virtual uint32_t load_http_info(CacheHTTPInfoVector *info, struct Doc *doc, RefCountObj *block_ptr = nullptr);
+  bool is_pread_capable() override;
+  bool set_pin_in_cache(time_t time_pin) override;
+  time_t get_pin_in_cache() override;
+
+  // number of bytes to memset to 0 in the CacheVC when we free
+  // it. All member variables starting from vio are memset to 0.
+  // This variable is initialized in CacheVC constructor.
+  static int size_to_init;
+
+  // Start Region A
+  // This set of variables are not reset when the cacheVC is freed.
+  // A CacheVC must set these to the correct values whenever needed
+  // These are variables that are always set to the correct values
+  // before being used by the CacheVC
+  CacheKey key, first_key, earliest_key, update_key;
+  Dir dir, earliest_dir, overwrite_dir, first_dir;
+  // end Region A
+
+  // Start Region B
+  // These variables are individually cleared or reset when the
+  // CacheVC is freed. All these variables must be reset/cleared
+  // in free_CacheVC.
+  Action _action;
+  CacheHTTPHdr request;
+  CacheHTTPInfoVector vector;
+  CacheHTTPInfo alternate;
+  Ptr<IOBufferData> buf;
+  Ptr<IOBufferData> first_buf;
+  Ptr<IOBufferBlock> blocks; // data available to write
+  Ptr<IOBufferBlock> writer_buf;
+
+  OpenDirEntry *od = nullptr;
+  AIOCallbackInternal io;
+  int alternate_index = CACHE_ALT_INDEX_DEFAULT; // preferred position in vector
+  LINK(CacheVC, opendir_link);
+#ifdef CACHE_STAT_PAGES
+  LINK(CacheVC, stat_link);
+#endif
+  // end Region B
+
+  // Start Region C
+  // These variables are memset to 0 when the structure is freed.
+  // The size of this region is size_to_init which is initialized
+  // in the CacheVC constructor. It assumes that vio is the start
+  // of this region.
+  // NOTE: NOTE: NOTE: If vio is NOT the start, then CHANGE the
+  // size_to_init initialization
+  VIO vio;
+  CacheFragType frag_type;
+  CacheHTTPInfo *info;
+  CacheHTTPInfoVector *write_vector;
+  const OverridableHttpConfigParams *params;
+  int header_len;        // for communicating with agg_copy
+  int frag_len;          // for communicating with agg_copy
+  uint32_t write_len;    // for communicating with agg_copy
+  uint32_t agg_len;      // for communicating with aggWrite
+  uint32_t write_serial; // serial of the final write for SYNC
+  Vol *vol;
+  Dir *last_collision;
+  Event *trigger;
+  CacheKey *read_key;
+  ContinuationHandler save_handler;
+  time_t pin_in_cache;
+  ink_hrtime start_time;
+  int op_type; // Index into the metrics array for this operation, rather than a CacheOpType (fewer casts)
+  int recursive;
+  int closed;
+  uint64_t seek_to;      // pread offset
+  int64_t offset;        // offset into 'blocks' of data to write
+  int64_t writer_offset; // offset of the writer for reading from a writer
+  int64_t length;        // length of data available to write
+  int64_t doc_pos;       // read position in 'buf'
+  uint64_t write_pos;    // length written
+  uint64_t total_len;    // total length written and available to write
+  uint64_t doc_len;      // total_length (of the selected alternate for HTTP)
+  uint64_t update_len;
+  int fragment;
+  int scan_msec_delay;
+  CacheVC *write_vc;
+  char *hostname;
+  int host_len;
+  int header_to_write_len;
+  void *header_to_write;
+  short writer_lock_retry;
+  union {
+    uint32_t flags;
+    struct {
+      unsigned int use_first_key           : 1;
+      unsigned int overwrite               : 1; // overwrite first_key Dir if it exists
+      unsigned int close_complete          : 1; // WRITE_COMPLETE is final
+      unsigned int sync                    : 1; // write to be committed to durable storage before WRITE_COMPLETE
+      unsigned int evacuator               : 1;
+      unsigned int single_fragment         : 1;
+      unsigned int evac_vector             : 1;
+      unsigned int lookup                  : 1;
+      unsigned int update                  : 1;
+      unsigned int remove                  : 1;
+      unsigned int remove_aborted_writers  : 1;
+      unsigned int open_read_timeout       : 1; // UNUSED
+      unsigned int data_done               : 1;
+      unsigned int read_from_writer_called : 1;
+      unsigned int not_from_ram_cache      : 1; // entire object was from ram cache
+      unsigned int rewrite_resident_alt    : 1;
+      unsigned int readers                 : 1;
+      unsigned int doc_from_ram_cache      : 1;
+      unsigned int hit_evacuate            : 1;
+      unsigned int compressed_in_ram       : 1; // compressed state in ram cache
+      unsigned int allow_empty_doc         : 1; // used for cache empty http document
+    } f;
+  };
+  // BTF optimization used to skip reading stuff in cache partition that doesn't contain any
+  // dir entries.
+  char *scan_vol_map;
+  // BTF fix to handle objects that overlapped over two different reads,
+  // this is how much we need to back up the buffer to get the start of the overlapping object.
+  off_t scan_fix_buffer_offset;
+  // end region C
+};
+
+LINK_DEFINITION(CacheVC, opendir_link)
diff --git a/iocore/cache/HttpTransactCache.h b/include/iocore/cache/HttpTransactCache.h
similarity index 100%
rename from iocore/cache/HttpTransactCache.h
rename to include/iocore/cache/HttpTransactCache.h
diff --git a/iocore/cache/I_Store.h b/include/iocore/cache/Store.h
similarity index 100%
rename from iocore/cache/I_Store.h
rename to include/iocore/cache/Store.h
diff --git a/include/iocore/dns/DNS.h b/include/iocore/dns/DNS.h
new file mode 100644
index 0000000000..b34fa61713
--- /dev/null
+++ b/include/iocore/dns/DNS.h
@@ -0,0 +1,36 @@
+/** @file
+
+  A brief file description
+
+  @section license License
+
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ */
+
+/****************************************************************************
+
+  DNS.h
+
+
+ ****************************************************************************/
+
+#pragma once
+
+#include "EventSystem.h"
+#include "HostDB.h"
+#include "Net.h"
+#include "DNSProcessor.h"
diff --git a/iocore/dns/DNSEventIO.h b/include/iocore/dns/DNSEventIO.h
similarity index 100%
rename from iocore/dns/DNSEventIO.h
rename to include/iocore/dns/DNSEventIO.h
diff --git a/include/iocore/dns/DNSProcessor.h b/include/iocore/dns/DNSProcessor.h
new file mode 100644
index 0000000000..5f455dda40
--- /dev/null
+++ b/include/iocore/dns/DNSProcessor.h
@@ -0,0 +1,231 @@
+/** @file
+
+  A brief file description
+
+  @section license License
+
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ */
+
+#pragma once
+
+#include "tscore/ink_resolver.h"
+#include "EventSystem.h"
+#include "SRV.h"
+
+// Events
+#define DNS_EVENT_LOOKUP DNS_EVENT_EVENTS_START
+
+const int DOMAIN_SERVICE_PORT = NAMESERVER_PORT;
+
+const int MAX_DNS_REQUEST_LEN  = NS_PACKETSZ;
+const int MAX_DNS_RESPONSE_LEN = 65536;
+const int DNS_RR_MAX_COUNT     = (MAX_DNS_RESPONSE_LEN - HFIXEDSZ + RRFIXEDSZ - 1) / RRFIXEDSZ;
+const int DNS_MAX_ALIASES      = DNS_RR_MAX_COUNT;
+const int DNS_MAX_ADDRS        = DNS_RR_MAX_COUNT;
+const int DNS_HOSTBUF_SIZE     = MAX_DNS_RESPONSE_LEN;
+
+/**
+  All buffering required to handle a DNS receipt. For asynchronous DNS,
+  only one HostEntBuf will exist in the system. For synchronous DNS,
+  one will exist per call until the user deletes them.
+
+*/
+struct HostEnt : RefCountObj {
+  struct hostent ent = {.h_name = nullptr, .h_aliases = nullptr, .h_addrtype = 0, .h_length = 0, .h_addr_list = nullptr};
+  uint32_t ttl       = 0;
+  int packet_size    = 0;
+  char buf[MAX_DNS_RESPONSE_LEN]         = {0};
+  u_char *host_aliases[DNS_MAX_ALIASES]  = {nullptr};
+  u_char *h_addr_ptrs[DNS_MAX_ADDRS + 1] = {nullptr};
+  u_char hostbuf[DNS_HOSTBUF_SIZE]       = {0};
+  SRVHosts srv_hosts;
+  bool good = true;
+  bool isNameError();
+  void free() override;
+};
+
+extern EventType ET_DNS;
+
+struct DNSHandler;
+
+/** Data for a DNS query.
+ * This is either a name for a standard query or an IP address for reverse DNS.
+ * Its type should be indicated by other parameters, generally the query type.
+ * - T_PTR: IP Address
+ * - T_A, T_SRV: Name
+ */
+union DNSQueryData {
+  std::string_view name; ///< Look up a name.
+  IpAddr const *addr;    ///< Reverse DNS lookup.
+
+  DNSQueryData(std::string_view tv) : name(tv) {}
+  DNSQueryData(IpAddr const *a) : addr(a) {}
+};
+
+struct DNSProcessor : public Processor {
+  // Public Interface
+  //
+
+  /// Options for host name resolution.
+  struct Options {
+    using self_type = Options; ///< Self reference type.
+
+    /// Query handler to use.
+    /// Default: single threaded handler.
+    DNSHandler *handler = nullptr;
+    /// Query timeout value.
+    /// Default: @c DEFAULT_DNS_TIMEOUT (or as set in records.yaml)
+    int timeout = 0; ///< Timeout value for request.
+    /// Host resolution style.
+    /// Default: IPv4, IPv6 ( @c HOST_RES_IPV4 )
+    HostResStyle host_res_style = HOST_RES_IPV4;
+
+    /// Default constructor.
+    Options();
+
+    /// Set @a handler option.
+    /// @return This object.
+    self_type &setHandler(DNSHandler *handler);
+
+    /// Set @a timeout option.
+    /// @return This object.
+    self_type &setTimeout(int timeout);
+
+    /// Set host query @a style option.
+    /// @return This object.
+    self_type &setHostResStyle(HostResStyle style);
+
+    /// Reset to default constructed values.
+    /// @return This object.
+    self_type &reset();
+  };
+
+  // DNS lookup
+  //   calls: cont->handleEvent( DNS_EVENT_LOOKUP, HostEnt *ent) on success
+  //          cont->handleEvent( DNS_EVENT_LOOKUP, nullptr) on failure
+  // NOTE: the HostEnt *block is freed when the function returns
+  //
+
+  Action *gethostbyname(Continuation *cont, const char *name, Options const &opt);
+  Action *gethostbyname(Continuation *cont, std::string_view name, Options const &opt);
+  Action *getSRVbyname(Continuation *cont, const char *name, Options const &opt);
+  Action *getSRVbyname(Continuation *cont, std::string_view name, Options const &opt);
+  Action *gethostbyaddr(Continuation *cont, IpAddr const *ip, Options const &opt);
+
+  // Processor API
+  //
+  /* currently dns system uses event threads
+   * dont pass any value to the call */
+  int start(int no_of_extra_dns_threads = 0, size_t stacksize = DEFAULT_STACKSIZE) override;
+
+  // Open/close a link to a 'named' (done in start())
+  //
+  void open(sockaddr const *ns = nullptr);
+
+  DNSProcessor();
+
+  // private:
+  //
+  EThread *thread     = nullptr;
+  DNSHandler *handler = nullptr;
+  ts_imp_res_state l_res;
+  IpEndpoint local_ipv6;
+  IpEndpoint local_ipv4;
+
+  /** Internal implementation for all getXbyY methods.
+      For host resolution queries pass @c T_A for @a type. It will be adjusted
+      as needed based on @a opt.host_res_style.
+
+      For address resolution ( @a type is @c T_PTR ), @a x should be a
+      @c sockaddr cast to  @c char @c const* .
+   */
+  Action *getby(DNSQueryData x, int type, Continuation *cont, Options const &opt);
+
+  void dns_init();
+};
+
+//
+// Global data
+//
+extern DNSProcessor dnsProcessor;
+
+//
+// Inline Functions
+//
+
+inline Action *
+DNSProcessor::getSRVbyname(Continuation *cont, const char *name, Options const &opt)
+{
+  return getby(std::string_view(name), T_SRV, cont, opt);
+}
+
+inline Action *
+DNSProcessor::getSRVbyname(Continuation *cont, std::string_view name, Options const &opt)
+{
+  return getby(name, T_SRV, cont, opt);
+}
+
+inline Action *
+DNSProcessor::gethostbyname(Continuation *cont, const char *name, Options const &opt)
+{
+  return getby(std::string_view(name), T_A, cont, opt);
+}
+
+inline Action *
+DNSProcessor::gethostbyname(Continuation *cont, std::string_view name, Options const &opt)
+{
+  return getby(name, T_A, cont, opt);
+}
+
+inline Action *
+DNSProcessor::gethostbyaddr(Continuation *cont, IpAddr const *addr, Options const &opt)
+{
+  return getby(addr, T_PTR, cont, opt);
+}
+
+inline DNSProcessor::Options::Options() {}
+
+inline DNSProcessor::Options &
+DNSProcessor::Options::setHandler(DNSHandler *h)
+{
+  handler = h;
+  return *this;
+}
+
+inline DNSProcessor::Options &
+DNSProcessor::Options::setTimeout(int t)
+{
+  timeout = t;
+  return *this;
+}
+
+inline DNSProcessor::Options &
+DNSProcessor::Options::setHostResStyle(HostResStyle style)
+{
+  host_res_style = style;
+  return *this;
+}
+
+inline DNSProcessor::Options &
+DNSProcessor::Options::reset()
+{
+  *this = Options();
+  return *this;
+}
+
+void ink_dns_init(ts::ModuleVersion version);
diff --git a/iocore/dns/SRV.h b/include/iocore/dns/SRV.h
similarity index 100%
rename from iocore/dns/SRV.h
rename to include/iocore/dns/SRV.h
diff --git a/include/iocore/dns/SplitDNS.h b/include/iocore/dns/SplitDNS.h
new file mode 100644
index 0000000000..d5ef0a0ba1
--- /dev/null
+++ b/include/iocore/dns/SplitDNS.h
@@ -0,0 +1,36 @@
+/** @file
+
+  A brief file description
+
+  @section license License
+
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ */
+
+/*****************************************************************************
+ *
+ * I_SplitDNS.h - Interface to DNS server selection
+ *
+ *
+ ****************************************************************************/
+
+#pragma once
+
+#include "SplitDNSProcessor.h"
+#include "tscore/Version.h"
+
+static constexpr ts::ModuleVersion SPLITDNS_MODULE_PUBLIC_VERSION(1, 0, ts::ModuleVersion::PUBLIC);
diff --git a/iocore/dns/I_SplitDNSProcessor.h b/include/iocore/dns/SplitDNSProcessor.h
similarity index 100%
rename from iocore/dns/I_SplitDNSProcessor.h
rename to include/iocore/dns/SplitDNSProcessor.h
diff --git a/include/iocore/eventsystem/Action.h b/include/iocore/eventsystem/Action.h
new file mode 100644
index 0000000000..666c1c7de4
--- /dev/null
+++ b/include/iocore/eventsystem/Action.h
@@ -0,0 +1,196 @@
+/** @file
+
+  Generic interface which enables any event or async activity to be cancelled
+
+  @section license License
+
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+ */
+
+#pragma once
+
+#include "tscore/ink_platform.h"
+#include "Thread.h"
+#include "Continuation.h"
+
+/**
+  Represents an operation initiated on a Processor.
+
+  The Action class is an abstract representation of an operation
+  being executed by some Processor. A reference to an Action object
+  allows you to cancel an ongoing asynchronous operation before it
+  completes. This means that the Continuation specified for the
+  operation will not be called back.
+
+  Actions or classes derived from Action are the typical return
+  type of methods exposed by Processors in the Event System and
+  throughout the IO Core libraries.
+
+  The canceller of an action must be the state machine that will
+  be called back by the task and that state machine's lock must be
+  held while calling cancel.
+
+  Processor implementers:
+
+  You must ensure that no events are sent to the state machine after
+  the operation has been cancelled appropriately.
+
+  Returning an Action:
+
+  Processor functions that are asynchronous must return actions to
+  allow the calling state machine to cancel the task before completion.
+  Because some processor functions are reentrant, they can call
+  back the state machine before the returning from the call that
+  creates the actions. To handle this case, special values are
+  returned in place of an action to indicate to the state machine
+  that the action is already completed.
+
+    - @b ACTION_RESULT_DONE The processor has completed the task
+      and called the state machine back inline.
+    - @b ACTION_RESULT_INLINE Not currently used.
+    - @b ACTION_RESULT_IO_ERROR Not currently used.
+
+  To make matters more complicated, it's possible if the result is
+  ACTION_RESULT_DONE that state machine deallocated itself on the
+  reentrant callback. Thus, state machine implementers MUST either
+  use a scheme to never deallocate their machines on reentrant
+  callbacks OR immediately check the returned action when creating
+  an asynchronous task and if it is ACTION_RESULT_DONE neither read
+  nor write any state variables. With either method, it's imperative
+  that the returned action always be checked for special values and
+  the value handled accordingly.
+
+  Allocation policy:
+
+  Actions are allocated by the Processor performing the actions.
+  It is the processor's responsibility to handle deallocation once
+  the action is complete or cancelled. A state machine MUST NOT
+  access an action once the operation that returned the Action has
+  completed or it has cancelled the Action.
+
+  Action pointer sanity checks must also check whether the lowest
+  bit of the pointer is 1. If it is 1, then the value must not be
+  treated as a pointer, and should be used as one of the values
+  defined below (e.g. ACTION_RESULT_DONE).
+
+*/
+class Action
+{
+public:
+  /**
+    Continuation that initiated this action.
+
+    The reference to the initiating continuation is only used to
+    verify that the action is being cancelled by the correct
+    continuation.  This field should not be accessed or modified
+    directly by the state machine.
+
+  */
+  Continuation *continuation = nullptr;
+
+  /**
+    Reference to the Continuation's lock.
+
+    Keeps a reference to the Continuation's lock to preserve the
+    access to the cancelled field valid even when the state machine
+    has been deallocated. This field should not be accessed or
+    modified directly by the state machine.
+
+  */
+  Ptr<ProxyMutex> mutex;
+
+  /**
+    Internal flag used to indicate whether the action has been
+    cancelled.
+
+    This flag is set after a call to cancel or cancel_action and
+    it should not be accessed or modified directly by the state
+    machine.
+
+  */
+  bool cancelled = false;
+
+  /**
+    Cancels the asynchronous operation represented by this action.
+
+    This method is called by state machines willing to cancel an
+    ongoing asynchronous operation. Classes derived from Action may
+    perform additional steps before flagging this action as cancelled.
+    There are certain rules that must be followed in order to cancel
+    an action (see the Remarks section).
+
+    @param c Continuation associated with this Action.
+
+  */
+  virtual void
+  cancel(Continuation *c = nullptr)
+  {
+    ink_assert(!c || c == continuation);
+    ink_assert(!cancelled);
+    cancelled = true;
+  }
+
+  /**
+    Cancels the asynchronous operation represented by this action.
+
+    This method is called by state machines willing to cancel an
+    ongoing asynchronous operation. There are certain rules that
+    must be followed in order to cancel an action (see the Remarks
+    section).
+
+    @param c Continuation associated with this Action.
+
+  */
+  void
+  cancel_action(Continuation *c = nullptr)
+  {
+    ink_assert(!c || c == continuation);
+    ink_assert(!cancelled);
+    cancelled = true;
+  }
+
+  Continuation *
+  operator=(Continuation *acont)
+  {
+    continuation = acont;
+    if (acont) {
+      mutex = acont->mutex;
+    } else {
+      mutex = nullptr;
+    }
+    return acont;
+  }
+
+  /**
+    Constructor of the Action object. Processor implementers are
+    responsible for associating this action with the proper
+    Continuation.
+
+  */
+  Action() {}
+  virtual ~Action() {}
+};
+
+#define ACTION_RESULT_DONE MAKE_ACTION_RESULT(1)
+#define ACTION_IO_ERROR    MAKE_ACTION_RESULT(2)
+
+// Use these classes by
+// #define ACTION_RESULT_HOST_DB_OFFLINE
+//   MAKE_ACTION_RESULT(ACTION_RESULT_HOST_DB_BASE + 0)
+
+#define MAKE_ACTION_RESULT(_x) (Action *)(((uintptr_t)((_x << 1) + 1)))
diff --git a/include/iocore/eventsystem/ConfigProcessor.h b/include/iocore/eventsystem/ConfigProcessor.h
new file mode 100644
index 0000000000..ea6d33abf1
--- /dev/null
+++ b/include/iocore/eventsystem/ConfigProcessor.h
@@ -0,0 +1,117 @@
+/** @file
+
+  A brief file description
+
+  @section license License
+
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ */
+
+#pragma once
+
+#include <atomic>
+
+#include "Tasks.h"
+
+class ProxyMutex;
+
+#define MAX_CONFIGS 100
+
+using ConfigInfo = RefCountObj;
+
+class ConfigProcessor
+{
+public:
+  ConfigProcessor() = default;
+
+  enum {
+    // The number of seconds to wait before garbage collecting stale ConfigInfo objects. There's
+    // no good reason to tune this, outside of regression tests, so don't.
+    CONFIG_PROCESSOR_RELEASE_SECS = 60
+  };
+
+  template <typename ClassType, typename ConfigType> struct scoped_config {
+    scoped_config() : ptr(ClassType::acquire()) {}
+    ~scoped_config() { ClassType::release(ptr); }
+    operator bool() const { return ptr != nullptr; }
+    operator const ConfigType *() const { return ptr; }
+    const ConfigType *
+    operator->() const
+    {
+      return ptr;
+    }
+
+  private:
+    ConfigType *ptr;
+  };
+
+  unsigned int set(unsigned int id, ConfigInfo *info, unsigned timeout_secs = CONFIG_PROCESSOR_RELEASE_SECS);
+  ConfigInfo *get(unsigned int id);
+  void release(unsigned int id, ConfigInfo *data);
+
+public:
+  std::atomic<ConfigInfo *> infos[MAX_CONFIGS] = {nullptr};
+  std::atomic<int> ninfos{0};
+};
+
+// A Continuation wrapper that calls the static reconfigure() method of the given class.
+template <typename UpdateClass> struct ConfigUpdateContinuation : public Continuation {
+  int
+  update(int /* etype */, void * /* data */)
+  {
+    UpdateClass::reconfigure();
+    delete this;
+    return EVENT_DONE;
+  }
+
+  ConfigUpdateContinuation(Ptr<ProxyMutex> &m) : Continuation(m.get()) { SET_HANDLER(&ConfigUpdateContinuation::update); }
+};
+
+template <typename UpdateClass>
+int
+ConfigScheduleUpdate(Ptr<ProxyMutex> &mutex)
+{
+  eventProcessor.schedule_imm(new ConfigUpdateContinuation<UpdateClass>(mutex), ET_TASK);
+  return 0;
+}
+
+template <typename UpdateClass> struct ConfigUpdateHandler {
+  ConfigUpdateHandler() : mutex(new_ProxyMutex()) {}
+  // The mutex member is ref-counted so should not explicitly free it
+  ~ConfigUpdateHandler() {}
+  int
+  attach(const char *name)
+  {
+    return REC_RegisterConfigUpdateFunc(name, ConfigUpdateHandler::update, this);
+  }
+
+private:
+  static int
+  update(const char *name, RecDataT /* data_type ATS_UNUSED */, RecData /* data ATS_UNUSED */, void *cookie)
+  {
+    ConfigUpdateHandler *self = static_cast<ConfigUpdateHandler *>(cookie);
+
+    Dbg(_dbg_ctl, "%s(%s)", __PRETTY_FUNCTION__, name);
+    return ConfigScheduleUpdate<UpdateClass>(self->mutex);
+  }
+
+  Ptr<ProxyMutex> mutex;
+
+  inline static DbgCtl _dbg_ctl{"config"};
+};
+
+extern ConfigProcessor configProcessor;
diff --git a/include/iocore/eventsystem/Continuation.h b/include/iocore/eventsystem/Continuation.h
new file mode 100644
index 0000000000..984819e357
--- /dev/null
+++ b/include/iocore/eventsystem/Continuation.h
@@ -0,0 +1,281 @@
+/** @file
+
+  A brief file description
+
+  @section license License
+
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  @section details Details
+
+  Continuations have a handleEvent() method to invoke them. Users
+  can determine the behavior of a Continuation by supplying a
+  "ContinuationHandler" (member function name) which is invoked
+  when events arrive. This function can be changed with the
+  "setHandler" method.
+
+  Continuations can be subclassed to add additional state and
+  methods.
+
+ */
+
+#pragma once
+
+#include "tscore/ink_platform.h"
+#include "tscore/List.h"
+#include "Lock.h"
+#include "tscore/ContFlags.h"
+
+class Continuation;
+class ContinuationQueue;
+class Processor;
+class ProxyMutex;
+class EThread;
+class Event;
+
+extern EThread *this_ethread();
+extern EThread *this_event_thread();
+
+//////////////////////////////////////////////////////////////////////////////
+//
+//  Constants and Type Definitions
+//
+//////////////////////////////////////////////////////////////////////////////
+
+#define CONTINUATION_EVENT_NONE 0
+
+#define CONTINUATION_DONE 0
+#define CONTINUATION_CONT 1
+
+using ContinuationHandler = int (Continuation::*)(int, void *);
+
+// Convert event handler pointer fp to type ContinuationHandler, but with a compiler error if class C is not
+// derived from the class Continuation.
+//
+template <class C, typename T>
+constexpr ContinuationHandler
+continuation_handler_void_ptr(int (C::*fp)(int, T *))
+{
+  auto fp2 = reinterpret_cast<int (C::*)(int, void *)>(fp);
+
+  // We keep this a static_cast for added static type analysis from the
+  // compiler. If a compiler warning is generated for the following line of
+  // code of the type "-Werror=shift-negative-value", then this may be an issue
+  // with multiple inheritance of the C templated type. Make sure that for type
+  // C the Continuation parent is listed first (either directly or indirectly
+  // via the inheritance tree) before any other parent in the multiple class
+  // hierarchy of C.
+  return static_cast<ContinuationHandler>(fp2);
+}
+
+// Overload for nullptr.
+//
+constexpr ContinuationHandler
+continuation_handler_void_ptr(std::nullptr_t)
+{
+#undef X
+#if !defined(__GNUC__)
+#define X 1
+#else
+#define X (__GNUC__ > 7)
+#endif
+#if X
+  static_assert(!static_cast<ContinuationHandler>(nullptr));
+#endif
+#undef X
+
+  return static_cast<ContinuationHandler>(nullptr);
+}
+
+class force_VFPT_to_top
+{
+public:
+  virtual ~force_VFPT_to_top() {}
+};
+
+/**
+  Base class for all state machines to receive notification of
+  events.
+
+  The Continuation class represents the main abstraction mechanism
+  used throughout the IO Core Event System to communicate its users
+  the occurrence of an event. A Continuation is a lightweight data
+  structure that implements a single method with which the user is
+  called back.
+
+  Continuations are typically subclassed in order to implement
+  event-driven state machines. By including additional state and
+  methods, continuations can combine state with control flow, and
+  they are generally used to support split-phase, event-driven
+  control flow.
+
+  Given the multithreaded nature of the Event System, every
+  continuation carries a reference to a ProxyMutex object to protect
+  its state and ensure atomic operations. This ProxyMutex object
+  must be allocated by continuation-derived classes or by clients
+  of the IO Core Event System and it is required as a parameter to
+  the Continuation's class constructor.
+
+*/
+
+class Continuation : private force_VFPT_to_top
+{
+public:
+  /**
+    The current continuation handler function.
+
+    The current handler should not be set directly. In order to
+    change it, first acquire the Continuation's lock and then use
+    the SET_HANDLER macro which takes care of the type casting
+    issues.
+
+  */
+  ContinuationHandler handler = nullptr;
+
+#ifdef DEBUG
+  const char *handler_name = nullptr;
+#endif
+
+  /**
+    The Continuation's lock.
+
+    A reference counted pointer to the Continuation's lock. This
+    lock is initialized in the constructor and should not be set
+    directly.
+
+    TODO:  make this private.
+
+  */
+  Ptr<ProxyMutex> mutex;
+
+  ProxyMutex *
+  getMutex() const
+  {
+    return mutex.get();
+  }
+
+  /**
+    Link to other continuations.
+
+    A doubly-linked element to allow Lists of Continuations to be
+    assembled.
+
+  */
+  LINK(Continuation, link);
+
+  /**
+    Contains values for debug_override and future flags that
+    needs to be thread local while this continuation is running
+  */
+  ContFlags control_flags;
+
+  EThread *thread_affinity = nullptr;
+
+  bool
+  setThreadAffinity(EThread *ethread)
+  {
+    if (ethread != nullptr) {
+      thread_affinity = ethread;
+      return true;
+    }
+    return false;
+  }
+
+  EThread *
+  getThreadAffinity()
+  {
+    return thread_affinity;
+  }
+
+  void
+  clearThreadAffinity()
+  {
+    thread_affinity = nullptr;
+  }
+
+  /**
+    Receives the event code and data for an Event.
+
+    This function receives the event code and data for an event and
+    forwards them to the current continuation handler. The processor
+    calling back the continuation is responsible for acquiring its
+    lock.  If the lock is present and not held, this method will assert.
+
+    @param event Event code to be passed at callback (Processor specific).
+    @param data General purpose data related to the event code (Processor specific).
+    @return State machine and processor specific return code.
+
+  */
+  TS_INLINE int
+  handleEvent(int event = CONTINUATION_EVENT_NONE, void *data = nullptr)
+  {
+    // If there is a lock, we must be holding it on entry
+    ink_release_assert(!mutex || mutex->thread_holding == this_ethread());
+    return (this->*handler)(event, data);
+  }
+
+protected:
+  /**
+    Constructor of the Continuation object. It should not be used
+    directly. Instead create an object of a derived type.
+
+    @param amutex Lock to be set for this Continuation.
+
+  */
+  explicit Continuation(ProxyMutex *amutex = nullptr);
+  explicit Continuation(Ptr<ProxyMutex> &amutex);
+};
+
+/**
+  Sets the Continuation's handler. The preferred mechanism for
+  setting the Continuation's handler.
+
+  @param _h Pointer to the function used to callback with events.
+
+*/
+#ifdef DEBUG
+#define SET_HANDLER(_h) (handler = continuation_handler_void_ptr(_h), handler_name = #_h)
+#else
+#define SET_HANDLER(_h) (handler = continuation_handler_void_ptr(_h))
+#endif
+
+/**
+  Sets a Continuation's handler.
+
+  The preferred mechanism for setting the Continuation's handler.
+
+  @param _c Pointer to a Continuation whose handler is being set.
+  @param _h Pointer to the function used to callback with events.
+
+*/
+#ifdef DEBUG
+#define SET_CONTINUATION_HANDLER(_c, _h) (_c->handler = continuation_handler_void_ptr(_h), _c->handler_name = #_h)
+#else
+#define SET_CONTINUATION_HANDLER(_c, _h) (_c->handler = continuation_handler_void_ptr(_h))
+#endif
+
+inline Continuation::Continuation(Ptr<ProxyMutex> &amutex) : mutex(amutex)
+{
+  // Pick up the control flags from the creating thread
+  this->control_flags.set_flags(get_cont_flags().get_flags());
+}
+
+inline Continuation::Continuation(ProxyMutex *amutex) : mutex(amutex)
+{
+  // Pick up the control flags from the creating thread
+  this->control_flags.set_flags(get_cont_flags().get_flags());
+}
diff --git a/include/iocore/eventsystem/EThread.h b/include/iocore/eventsystem/EThread.h
new file mode 100644
index 0000000000..e547656688
--- /dev/null
+++ b/include/iocore/eventsystem/EThread.h
@@ -0,0 +1,644 @@
+/** @file
+
+  A brief file description
+
+  @section license License
+
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+ */
+
+#pragma once
+
+#include "tscore/ink_platform.h"
+#include "tscore/ink_rand.h"
+#include "tscore/Version.h"
+#include "Thread.h"
+#include "PriorityEventQueue.h"
+#include "ProtectedQueue.h"
+#include "tscpp/util/Histogram.h"
+
+// TODO: This would be much nicer to have "run-time" configurable (or something)
+#define PER_THREAD_DATA (1024 * 1024)
+
+// This is not used by the cache anymore, it uses proxy.config.cache.mutex_retry_delay
+// instead.
+#define MUTEX_RETRY_DELAY HRTIME_MSECONDS(20)
+
+class DiskHandler;
+struct EventIO;
+
+class ServerSessionPool;
+class PreWarmQueue;
+
+class Event;
+class Continuation;
+class ConnectingPool;
+
+enum ThreadType {
+  REGULAR = 0,
+  DEDICATED,
+};
+
+/**
+  Event System specific type of thread.
+
+  The EThread class is the type of thread created and managed by
+  the Event System. It is one of the available interfaces for
+  scheduling events in the event system (another two are the Event
+  and EventProcessor classes).
+
+  In order to handle events, each EThread object has two event
+  queues, one external and one internal. The external queue is
+  provided for users of the EThread (clients) to append events to
+  that particular thread. Since it can be accessed by other threads
+  at the same time, operations using it must proceed in an atomic
+  fashion.
+
+  The internal queue, in the other hand, is used exclusively by the
+  EThread to process timed events within a certain time frame. These
+  events are queued internally and they may come from the external
+  queue as well.
+
+  Scheduling Interface:
+
+  There are eight scheduling functions provided by EThread and
+  they are a wrapper around their counterparts in EventProcessor.
+
+  @see EventProcessor
+  @see Event
+
+*/
+class EThread : public Thread
+{
+public:
+  static thread_local EThread *this_ethread_ptr;
+
+  /** Default wait interval for polling or delaying
+
+      This used to be known as net_config_poll_timeout, but was being used
+      (and externed) through the codebase so was causing problems with linking.
+
+      It is still configured as "proxy.config.net.poll_timeout" for now
+   */
+  static int default_wait_interval_ms;
+
+  /** Handler for tail of event loop.
+
+      The event loop should not spin. To avoid that a tail handler is called to block for a limited time.
+      This is a protocol class that defines the interface to the handler.
+  */
+  class LoopTailHandler
+  {
+  public:
+    /** Called at the end of the event loop to block.
+        @a timeout is the maximum length of time (in ns) to block.
+    */
+    virtual int waitForActivity(ink_hrtime timeout) = 0;
+    /** Unblock.
+
+        This is required to unblock (wake up) the block created by calling @a cb.
+    */
+    virtual void signalActivity() = 0;
+
+    virtual ~LoopTailHandler() {}
+  };
+
+  /*-------------------------------------------------------*\
+  |  Common Interface                                       |
+  \*-------------------------------------------------------*/
+
+  /**
+    Schedules the continuation on this EThread to receive an event
+    as soon as possible.
+
+    Forwards to the EventProcessor the schedule of the callback to
+    the continuation 'c' as soon as possible. The event is assigned
+    to EThread.
+
+    @param c Continuation to be called back as soon as possible.
+    @param callback_event Event code to be passed back to the
+      continuation's handler. See the EventProcessor class.
+    @param cookie User-defined value or pointer to be passed back
+      in the Event's object cookie field.
+    @return Reference to an Event object representing the scheduling
+      of this callback.
+
+  */
+  Event *schedule_imm(Continuation *c, int callback_event = EVENT_IMMEDIATE, void *cookie = nullptr);
+
+  /**
+    Schedules the continuation on this EThread to receive an event
+    at the given timeout.
+
+    Forwards the request to the EventProcessor to schedule the
+    callback to the continuation 'c' at the time specified in
+    'atimeout_at'. The event is assigned to this EThread.
+
+    @param c Continuation to be called back at the time specified
+      in 'atimeout_at'.
+    @param atimeout_at Time value at which to callback.
+    @param callback_event Event code to be passed back to the
+      continuation's handler. See the EventProcessor class.
+    @param cookie User-defined value or pointer to be passed back
+      in the Event's object cookie field.
+    @return A reference to an Event object representing the scheduling
+      of this callback.
+
+  */
+  Event *schedule_at(Continuation *c, ink_hrtime atimeout_at, int callback_event = EVENT_INTERVAL, void *cookie = nullptr);
+
+  /**
+    Schedules the continuation on this EThread to receive an event
+    after the timeout elapses.
+
+    Instructs the EventProcessor to schedule the callback to the
+    continuation 'c' after the time specified in atimeout_in elapses.
+    The event is assigned to this EThread.
+
+    @param c Continuation to be called back after the timeout elapses.
+    @param atimeout_in Amount of time after which to callback.
+    @param callback_event Event code to be passed back to the
+      continuation's handler. See the EventProcessor class.
+    @param cookie User-defined value or pointer to be passed back
+      in the Event's object cookie field.
+    @return A reference to an Event object representing the scheduling
+      of this callback.
+
+  */
+  Event *schedule_in(Continuation *c, ink_hrtime atimeout_in, int callback_event = EVENT_INTERVAL, void *cookie = nullptr);
+
+  /**
+    Schedules the continuation on this EThread to receive an event
+    periodically.
+
+    Schedules the callback to the continuation 'c' in the EventProcessor
+    to occur every time 'aperiod' elapses. It is scheduled on this
+    EThread.
+
+    @param c Continuation to call back every time 'aperiod' elapses.
+    @param aperiod Duration of the time period between callbacks.
+    @param callback_event Event code to be passed back to the
+      continuation's handler. See the Remarks section in the
+      EventProcessor class.
+    @param cookie User-defined value or pointer to be passed back
+      in the Event's object cookie field.
+    @return A reference to an Event object representing the scheduling
+      of this callback.
+
+  */
+  Event *schedule_every(Continuation *c, ink_hrtime aperiod, int callback_event = EVENT_INTERVAL, void *cookie = nullptr);
+
+  /**
+    Schedules the continuation on this EThread to receive an event
+    as soon as possible.
+
+    Schedules the callback to the continuation 'c' as soon as
+    possible. The event is assigned to this EThread.
+
+    @param c Continuation to be called back as soon as possible.
+    @param callback_event Event code to be passed back to the
+      continuation's handler. See the EventProcessor class.
+    @param cookie User-defined value or pointer to be passed back
+      in the Event's object cookie field.
+    @return A reference to an Event object representing the scheduling
+      of this callback.
+
+  */
+  Event *schedule_imm_local(Continuation *c, int callback_event = EVENT_IMMEDIATE, void *cookie = nullptr);
+
+  /**
+    Schedules the continuation on this EThread to receive an event
+    at the given timeout.
+
+    Schedules the callback to the continuation 'c' at the time
+    specified in 'atimeout_at'. The event is assigned to this
+    EThread.
+
+    @param c Continuation to be called back at the time specified
+      in 'atimeout_at'.
+    @param atimeout_at Time value at which to callback.
+    @param callback_event Event code to be passed back to the
+      continuation's handler. See the EventProcessor class.
+    @param cookie User-defined value or pointer to be passed back
+      in the Event's object cookie field.
+    @return A reference to an Event object representing the scheduling
+      of this callback.
+
+  */
+  Event *schedule_at_local(Continuation *c, ink_hrtime atimeout_at, int callback_event = EVENT_INTERVAL, void *cookie = nullptr);
+
+  /**
+    Schedules the continuation on this EThread to receive an event
+    after the timeout elapses.
+
+    Schedules the callback to the continuation 'c' after the time
+    specified in atimeout_in elapses. The event is assigned to this
+    EThread.
+
+    @param c Continuation to be called back after the timeout elapses.
+    @param atimeout_in Amount of time after which to callback.
+    @param callback_event Event code to be passed back to the
+      continuation's handler. See the Remarks section in the
+      EventProcessor class.
+    @param cookie User-defined value or pointer to be passed back
+      in the Event's object cookie field.
+    @return A reference to an Event object representing the scheduling
+      of this callback.
+
+  */
+  Event *schedule_in_local(Continuation *c, ink_hrtime atimeout_in, int callback_event = EVENT_INTERVAL, void *cookie = nullptr);
+
+  /**
+    Schedules the continuation on this EThread to receive an event
+    periodically.
+
+    Schedules the callback to the continuation 'c' to occur every
+    time 'aperiod' elapses. It is scheduled on this EThread.
+
+    @param c Continuation to call back every time 'aperiod' elapses.
+    @param aperiod Duration of the time period between callbacks.
+    @param callback_event Event code to be passed back to the
+      continuation's handler. See the Remarks section in the
+      EventProcessor class.
+    @param cookie User-defined value or pointer to be passed back
+      in the Event's object cookie field.
+    @return A reference to an Event object representing the scheduling
+      of this callback.
+
+  */
+  Event *schedule_every_local(Continuation *c, ink_hrtime aperiod, int callback_event = EVENT_INTERVAL, void *cookie = nullptr);
+
+  /** Schedule an event called once when the thread is spawned.
+
+      This is useful only for regular threads and if called before @c Thread::start. The event will be
+      called first before the event loop.
+
+      @Note This will override the event for a dedicate thread so that this is called instead of the
+      event passed to the constructor.
+  */
+  Event *schedule_spawn(Continuation *c, int ev = EVENT_IMMEDIATE, void *cookie = nullptr);
+
+  // Set the tail handler.
+  void set_tail_handler(LoopTailHandler *handler);
+
+  void set_specific() override;
+
+  /* private */
+
+  Event *schedule_local(Event *e);
+
+  InkRand generator = static_cast<uint64_t>(ink_get_hrtime() ^ reinterpret_cast<uintptr_t>(this));
+
+  /*-------------------------------------------------------*\
+  |  UNIX Interface                                         |
+  \*-------------------------------------------------------*/
+
+  EThread();
+  EThread(ThreadType att, int anid);
+  EThread(ThreadType att, Event *e);
+  EThread(const EThread &)            = delete;
+  EThread &operator=(const EThread &) = delete;
+  ~EThread() override;
+
+  Event *schedule(Event *e);
+
+  /** Block of memory to allocate thread specific data e.g. stat system arrays. */
+  char thread_private[PER_THREAD_DATA];
+
+  /** Private Data for the Disk Processor. */
+  DiskHandler *diskHandler = nullptr;
+
+  /** Private Data for AIO. */
+  Que(Continuation, link) aio_ops;
+
+  ProtectedQueue EventQueueExternal;
+  PriorityEventQueue EventQueue;
+
+  static constexpr int NO_ETHREAD_ID = -1;
+  int id                             = NO_ETHREAD_ID;
+  unsigned int event_types           = 0;
+  bool is_event_type(EventType et);
+  void set_event_type(EventType et);
+
+  // Private Interface
+
+  void execute() override;
+  void execute_regular();
+  void process_queue(Que(Event, link) * NegativeQueue, int *ev_count, int *nq_count);
+  void process_event(Event *e, int calling_code);
+  void free_event(Event *e);
+  LoopTailHandler *tail_cb = &DEFAULT_TAIL_HANDLER;
+
+#if HAVE_EVENTFD
+  int evfd = ts::NO_FD;
+#else
+  int evpipe[2];
+#endif
+  EventIO *ep = nullptr;
+
+  ThreadType tt = REGULAR;
+  /** Initial event to call, before any scheduling.
+
+      For dedicated threads this is the only event called.
+      For regular threads this is called first before the event loop starts.
+      @internal For regular threads this is used by the EventProcessor to get called back after
+      the thread starts but before any other events can be dispatched to provide initializations
+      needed for the thread.
+  */
+  Event *start_event = nullptr;
+
+  ServerSessionPool *server_session_pool = nullptr;
+  PreWarmQueue *prewarm_queue            = nullptr;
+  ConnectingPool *connecting_pool        = nullptr;
+
+  /** Default handler used until it is overridden.
+
+      This uses the cond var wait in @a ExternalQueue.
+  */
+  class DefaultTailHandler : public LoopTailHandler
+  {
+    explicit DefaultTailHandler(ProtectedQueue &q) : _q(q) {}
+
+    int
+    waitForActivity(ink_hrtime timeout) override
+    {
+      _q.wait(ink_get_hrtime() + timeout);
+      return 0;
+    }
+    void
+    signalActivity() override
+    {
+      /* Try to acquire the `EThread::lock` of the Event Thread:
+       *   - Acquired, indicating that the Event Thread is sleep,
+       *               must send a wakeup signal to the Event Thread.
+       *   - Failed, indicating that the Event Thread is busy, do nothing.
+       */
+      (void)_q.try_signal();
+    }
+
+    ProtectedQueue &_q;
+
+    friend class EThread;
+  } DEFAULT_TAIL_HANDLER = DefaultTailHandler(EventQueueExternal);
+
+  struct Metrics {
+    using self_type = Metrics; ///< Self reference type.
+
+    /// Information about loops within the same time slice.
+    struct Slice {
+      using self_type = Slice;
+
+      /// Data for timing of the loop.
+      struct Duration {
+        ink_hrtime _start = 0;         ///< The time of the first loop for this sample. Used to mark valid entries.
+        ink_hrtime _min   = INT64_MAX; ///< Shortest loop time.
+        ink_hrtime _max   = 0;         ///< Longest loop time.
+        Duration()        = default;
+      } _duration;
+
+      /// Events in the slice.
+      struct Events {
+        int _min   = INT_MAX; ///< Minimum # of events in a loop.
+        int _max   = 0;       ///< Maximum # of events in a loop.
+        int _total = 0;       ///< Total # of events.
+        Events() {}
+      } _events;
+
+      int _count = 0; ///< # of times the loop executed.
+      int _wait  = 0; ///< # of timed wait for events
+
+      /** Record the loop start time.
+       *
+       * @param t Start time.
+       * @return @a this
+       */
+      self_type &record_loop_start(ink_hrtime t);
+
+      /** Record event loop duration.
+       *
+       * @param delta Duration of the loop.
+       * @return @a this.
+       */
+      self_type &record_loop_duration(ink_hrtime delta);
+
+      /** Record number of events in a loop.
+       *
+       * @param count Event count.
+       * @return
+       */
+      self_type &record_event_count(int count);
+
+      /// Add @a that to @a this data.
+      /// This embodies the custom logic per member concerning whether each is a sum, min, or max.
+      Slice &operator+=(Slice const &that);
+
+      /** Slice related statistics.
+          THE ORDER IS VERY SENSITIVE.
+          More than one part of the code depends on this exact order. Be careful and thorough when changing.
+      */
+      enum class STAT_ID {
+        LOOP_COUNT,      ///< # of event loops executed.
+        LOOP_EVENTS,     ///< # of events
+        LOOP_EVENTS_MIN, ///< min # of events dispatched in a loop
+        LOOP_EVENTS_MAX, ///< max # of events dispatched in a loop
+        LOOP_WAIT,       ///< # of loops that did a conditional wait.
+        LOOP_TIME_MIN,   ///< Shortest time spent in loop.
+        LOOP_TIME_MAX,   ///< Longest time spent in loop.
+      };
+      /// Number of statistics for a slice.
+      static constexpr unsigned N_STAT_ID = unsigned(STAT_ID::LOOP_TIME_MAX) + 1;
+
+      /// Statistic name stems.
+      /// These will be qualified by time scale.
+      static char const *const STAT_NAME[N_STAT_ID];
+
+      Slice() = default;
+    };
+
+    /** The number of slices.
+        This is a circular buffer, with one slice per second. We have a bit more than the required 1000
+        to provide sufficient slop for cross thread reading of the data (as only the current slice
+        is being updated).
+    */
+    static constexpr int N_SLICES = 1024;
+    /// The slices.
+    std::array<Slice, N_SLICES> _slice;
+
+    Slice *volatile current_slice = nullptr; ///< The current slice.
+
+    /** The number of time scales used in the event statistics.
+        Currently these are 10s, 100s, 1000s.
+    */
+    static constexpr unsigned N_TIMESCALES = 3;
+
+    /// # of samples for each time scale.
+    static constexpr std::array<unsigned, 3> SLICE_SAMPLE_COUNT = {10, 100, 1000};
+
+    /// Total # of stats created for slice metrics.
+    static constexpr unsigned N_SLICE_STATS = Slice::N_STAT_ID * N_TIMESCALES;
+
+    /// Back up the metric pointer, wrapping as needed.
+    Slice *prev_slice(Slice *current);
+    /// Advance the metric pointer, wrapping as needed.
+    Slice *next_slice(Slice *current);
+
+    /** Record a loop time sample in the histogram.
+     *
+     * @param delta Loop time.
+     * @return @a this
+     */
+    self_type &record_loop_time(ink_hrtime delta);
+
+    /** Record total api sample in the histogram.
+     *
+     * @param delta Duration.
+     * @return @a this
+     */
+    self_type &record_api_time(ink_hrtime delta);
+
+    /// Do any accumulated data decay that's required.
+    self_type &decay();
+
+    /// Base name for event loop histogram stats.
+    /// The actual stats are determined by the @c Histogram properties.
+    static constexpr swoc::TextView LOOP_HISTOGRAM_STAT_STEM = "proxy.process.eventloop.time.";
+    /// Base bucket size for @c Graph
+    static constexpr ts_milliseconds LOOP_HISTOGRAM_BUCKET_SIZE{5};
+
+    /// Histogram type. 7,2 provides a reasonable range (5-2560 ms) and accuracy.
+    using Graph = ts::Histogram<7, 2>;
+    Graph _loop_timing; ///< Event loop timings.
+    /// Base name for event loop histogram stats.
+    /// The actual stats are determined by the @c Histogram properties.
+    static constexpr swoc::TextView API_HISTOGRAM_STAT_STEM = "proxy.process.api.time.";
+    /// Base bucket size in milliseconds for plugin API timings.
+    static constexpr ts_milliseconds API_HISTOGRAM_BUCKET_SIZE{1};
+    Graph _api_timing; ///< Plugin API callout timings.
+
+    /// Data in the histogram needs to decay over time. To avoid races and locks the
+    /// summarizing thread bumps this to indicate a decay is needed and doesn't update if
+    /// this is non-zero. The event loop does the decay and decrements the count.
+    std::atomic<unsigned> _decay_count = 0;
+    /// Decay this often.
+    static inline std::chrono::duration _decay_delay = std::chrono::seconds{90};
+    /// Time of last decay.
+    static inline ts_clock::time_point _last_decay_time;
+
+    /// Total number of metric based statistics.
+    static constexpr unsigned N_STATS = N_SLICE_STATS + 2 * Graph::N_BUCKETS;
+
+    /// Summarize this instance into a global instance.
+    void summarize(self_type &global);
+  };
+
+  Metrics metrics;
+};
+
+// --- Inline implementation
+
+inline auto
+EThread::Metrics::Slice::record_loop_start(ink_hrtime t) -> self_type &
+{
+  _duration._start = t;
+  return *this;
+}
+
+inline auto
+EThread::Metrics::Slice::record_loop_duration(ink_hrtime delta) -> self_type &
+{
+  if (delta > _duration._max) {
+    _duration._max = delta;
+  }
+  if (delta < _duration._min) {
+    _duration._min = delta;
+  }
+  return *this;
+}
+
+inline auto
+EThread::Metrics::Slice::record_event_count(int count) -> self_type &
+{
+  if (count < _events._min) {
+    _events._min = count;
+  }
+  if (count > _events._max) {
+    _events._max = _count;
+  }
+  _events._total += count;
+  return *this;
+}
+
+inline EThread::Metrics::Slice *
+EThread::Metrics::prev_slice(EThread::Metrics::Slice *current)
+{
+  return --current < _slice.data() ? &_slice[N_SLICES - 1] : current;
+}
+
+inline EThread::Metrics::Slice *
+EThread::Metrics::next_slice(EThread::Metrics::Slice *current)
+{
+  return ++current > &_slice[N_SLICES - 1] ? _slice.data() : current;
+}
+
+inline auto
+EThread::Metrics::record_loop_time(ink_hrtime delta) -> self_type &
+{
+  static auto constexpr DIVISOR = std::chrono::duration_cast<ts_nanoseconds>(LOOP_HISTOGRAM_BUCKET_SIZE).count();
+  current_slice->record_loop_duration(delta);
+  _loop_timing(delta / DIVISOR);
+  return *this;
+}
+
+inline auto
+EThread::Metrics::record_api_time(ink_hrtime delta) -> self_type &
+{
+  static auto constexpr DIVISOR = std::chrono::duration_cast<ts_nanoseconds>(LOOP_HISTOGRAM_BUCKET_SIZE).count();
+  _api_timing(delta / DIVISOR);
+  return *this;
+}
+
+inline auto
+EThread::Metrics::decay() -> self_type &
+{
+  while (_decay_count) {
+    _loop_timing.decay();
+    _api_timing.decay();
+    --_decay_count;
+  }
+  return *this;
+}
+
+/**
+  This is used so that we dont use up operator new(size_t, void *)
+  which users might want to define for themselves.
+
+*/
+class ink_dummy_for_new
+{
+};
+
+inline void *
+operator new(size_t, ink_dummy_for_new *p)
+{
+  return (void *)p;
+}
+#define ETHREAD_GET_PTR(thread, offset) ((void *)((char *)(thread) + (offset)))
+
+extern EThread *this_ethread();
+
+extern int thread_max_heartbeat_mseconds;
diff --git a/include/iocore/eventsystem/Event.h b/include/iocore/eventsystem/Event.h
new file mode 100644
index 0000000000..2e84ad8d76
--- /dev/null
+++ b/include/iocore/eventsystem/Event.h
@@ -0,0 +1,292 @@
+/** @file
+
+  A brief file description
+
+  @section license License
+
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+ */
+
+#pragma once
+
+#include "tscore/ink_platform.h"
+#include "Action.h"
+
+//
+//  Defines
+//
+
+#define MAX_EVENTS_PER_THREAD 100000
+
+// Events
+
+#define EVENT_NONE      CONTINUATION_EVENT_NONE // 0
+#define EVENT_IMMEDIATE 1
+#define EVENT_INTERVAL  2
+#define EVENT_ERROR     3
+#define EVENT_CALL      4 // used internally in state machines
+#define EVENT_POLL      5 // negative event; activated on poll or epoll
+
+// Event callback return functions
+
+#define EVENT_DONE            CONTINUATION_DONE // 0
+#define EVENT_CONT            CONTINUATION_CONT // 1
+#define EVENT_RETURN          5
+#define EVENT_RESTART         6
+#define EVENT_RESTART_DELAYED 7
+
+// Event numbers block allocation
+// ** ALL NEW EVENT TYPES SHOULD BE ALLOCATED FROM BLOCKS LISTED HERE! **
+
+#define VC_EVENT_EVENTS_START                   100
+#define NET_EVENT_EVENTS_START                  200
+#define DISK_EVENT_EVENTS_START                 300
+#define HOSTDB_EVENT_EVENTS_START               500
+#define DNS_EVENT_EVENTS_START                  600
+#define CONFIG_EVENT_EVENTS_START               800
+#define LOG_EVENT_EVENTS_START                  900
+#define REFCOUNT_CACHE_EVENT_EVENTS_START       1000
+#define CACHE_EVENT_EVENTS_START                1100
+#define CACHE_DIRECTORY_EVENT_EVENTS_START      1200
+#define CACHE_DB_EVENT_EVENTS_START             1300
+#define HTTP_NET_CONNECTION_EVENT_EVENTS_START  1400
+#define HTTP_NET_VCONNECTION_EVENT_EVENTS_START 1500
+#define GC_EVENT_EVENTS_START                   1600
+#define TRANSFORM_EVENTS_START                  2000
+#define STAT_PAGES_EVENTS_START                 2100
+#define HTTP_SESSION_EVENTS_START               2200
+#define HTTP2_SESSION_EVENTS_START              2250
+#define HTTP_TUNNEL_EVENTS_START                2300
+#define HTTP_SCH_UPDATE_EVENTS_START            2400
+#define QUIC_EVENT_EVENTS_START                 2500
+#define HTTP3_SESSION_EVENTS_START              2600
+#define QPACK_EVENT_EVENTS_START                2700
+#define NT_ASYNC_CONNECT_EVENT_EVENTS_START     3000
+#define NT_ASYNC_IO_EVENT_EVENTS_START          3100
+#define RAFT_EVENT_EVENTS_START                 3200
+#define SIMPLE_EVENT_EVENTS_START               3300
+#define UPDATE_EVENT_EVENTS_START               3500
+#define AIO_EVENT_EVENTS_START                  3900
+#define BLOCK_CACHE_EVENT_EVENTS_START          4000
+#define UTILS_EVENT_EVENTS_START                5000
+#define INK_API_EVENT_EVENTS_START              60000
+#define SRV_EVENT_EVENTS_START                  62000
+#define REMAP_EVENT_EVENTS_START                63000
+
+// define misc events here
+#define ONE_WAY_TUNNEL_EVENT_PEER_CLOSE (SIMPLE_EVENT_EVENTS_START + 1)
+
+using EventType           = int;
+const int ET_CALL         = 0;
+const int MAX_EVENT_TYPES = 8; // conservative, these are dynamically allocated
+
+class EThread;
+
+/**
+  A type of Action returned by the EventProcessor. The Event class
+  is the type of Action returned by the EventProcessor as a result
+  of scheduling an operation. Unlike asynchronous operations
+  represented by actions, events never call reentrantly.
+
+  Besides being able to cancel an event (because it is an action),
+  you can also reschedule it once received.
+
+  <b>Remarks</b>
+
+  When rescheduling an event through any of the Event class
+  scheduling functions, state machines must not make these calls
+  in other thread other than the one that called them back. They
+  also must have acquired the continuation's lock before calling
+  any of the scheduling functions.
+
+  The rules for canceling an event are the same as those for
+  actions:
+
+  The canceler of an event must be the state machine that will be
+  called back by the task and that state machine's lock must be
+  held while calling cancel. Any reference to that event object
+  (ie. pointer) held by the state machine must not be used after
+  the cancellation.
+
+  Event Codes:
+
+  At the completion of an event, state machines use the event code
+  passed in through the Continuation's handler function to distinguish
+  the type of event and handle the data parameter accordingly. State
+  machine implementers should be careful when defining the event
+  codes since they can impact on other state machines presents. For
+  this reason, this numbers are usually allocated from a common
+  pool.
+
+  Time values:
+
+  The scheduling functions use a time parameter typed as ink_hrtime
+  for specifying the timeouts or periods. This is a nanosecond value
+  supported by libts and you should use the time functions and
+  macros defined in ink_hrtime.h.
+
+  The difference between the timeout specified for schedule_at and
+  schedule_in is that in the former it is an absolute value of time
+  that is expected to be in the future where in the latter it is
+  an amount of time to add to the current time (obtained with
+  ink_get_hrtime).
+
+*/
+class Event : public Action
+{
+public:
+  ///////////////////////////////////////////////////////////
+  // Common Interface                                      //
+  ///////////////////////////////////////////////////////////
+
+  /**
+     Reschedules this event immediately. Instructs the event object
+     to reschedule itself as soon as possible in the EventProcessor.
+
+     @param callback_event Event code to return at the completion
+      of this event. See the Remarks section.
+
+  */
+  void schedule_imm(int callback_event = EVENT_IMMEDIATE);
+
+  /**
+     Reschedules this event to callback at time 'atimeout_at'.
+     Instructs the event object to reschedule itself at the time
+     specified in atimeout_at on the EventProcessor.
+
+     @param atimeout_at Time at which to call the callback. See the Remarks section.
+     @param callback_event Event code to return at the completion of this event. See the Remarks section.
+
+  */
+  void schedule_at(ink_hrtime atimeout_at, int callback_event = EVENT_INTERVAL);
+
+  /**
+     Reschedules this event to callback at time 'atimeout_at'.
+     Instructs the event object to reschedule itself at the time
+     specified in atimeout_at on the EventProcessor.
+
+     @param atimeout_in Time at which to call the callback. See the Remarks section.
+     @param callback_event Event code to return at the completion of this event. See the Remarks section.
+
+  */
+  void schedule_in(ink_hrtime atimeout_in, int callback_event = EVENT_INTERVAL);
+
+  /**
+     Reschedules this event to callback every 'aperiod'. Instructs
+     the event object to reschedule itself to callback every 'aperiod'
+     from now.
+
+     @param aperiod Time period at which to call the callback. See the Remarks section.
+     @param callback_event Event code to return at the completion of this event. See the Remarks section.
+
+  */
+  void schedule_every(ink_hrtime aperiod, int callback_event = EVENT_INTERVAL);
+
+  // inherited from Action::cancel
+  // virtual void cancel(Continuation * c = nullptr);
+
+#ifdef ENABLE_EVENT_TRACKER
+  void set_location();
+  const void *get_location() const;
+#endif
+
+  void free();
+
+  EThread *ethread = nullptr;
+
+  unsigned int in_the_prot_queue     : 1;
+  unsigned int in_the_priority_queue : 1;
+  unsigned int immediate             : 1;
+  unsigned int globally_allocated    : 1;
+  unsigned int in_heap               : 4;
+  int callback_event = 0;
+
+  ink_hrtime timeout_at = 0;
+  ink_hrtime period     = 0;
+
+  /**
+    This field can be set when an event is created. It is returned
+    as part of the Event structure to the continuation when handleEvent
+    is called.
+
+  */
+  void *cookie = nullptr;
+
+  // Private
+
+  Event();
+
+  Event *init(Continuation *c, ink_hrtime atimeout_at = 0, ink_hrtime aperiod = 0);
+
+#ifdef ENABLE_TIME_TRACE
+  ink_hrtime start_time;
+#endif
+
+  // noncopyable: prevent unauthorized copies (Not implemented)
+  Event(const Event &)            = delete;
+  Event &operator=(const Event &) = delete;
+
+private:
+  void *operator new(size_t size); // use the fast allocators
+
+#ifdef ENABLE_EVENT_TRACKER
+  /**
+    Address of who scheduled this event
+    To get symbols, use backtrace_symbols(3) or external tools like `addr2line(1)` (Linux) or `atos(1)`(BSD).
+   */
+  const void *_location = nullptr;
+#endif
+
+public:
+  LINK(Event, link);
+
+  /*-------------------------------------------------------*\
+  | UNIX/non-NT Interface                                   |
+  \*-------------------------------------------------------*/
+
+#ifdef ONLY_USED_FOR_FIB_AND_BIN_HEAP
+  void *node_pointer;
+  void
+  set_node_pointer(void *x)
+  {
+    node_pointer = x;
+  }
+  void *
+  get_node_pointer()
+  {
+    return node_pointer;
+  }
+#endif
+
+#if defined(__GNUC__)
+  ~Event() override {}
+#endif
+};
+
+//
+// Event Allocator
+//
+extern ClassAllocator<Event> eventAllocator;
+
+#define EVENT_ALLOC(_a, _t) THREAD_ALLOC(_a, _t)
+#define EVENT_FREE(_p, _a, _t) \
+  _p->mutex = nullptr;         \
+  if (_p->globally_allocated)  \
+    ::_a.free(_p);             \
+  else                         \
+    THREAD_FREE(_p, _a, _t)
diff --git a/include/iocore/eventsystem/EventProcessor.h b/include/iocore/eventsystem/EventProcessor.h
new file mode 100644
index 0000000000..61fafcff35
--- /dev/null
+++ b/include/iocore/eventsystem/EventProcessor.h
@@ -0,0 +1,402 @@
+/** @file
+
+  A brief file description
+
+  @section license License
+
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ */
+
+#pragma once
+
+#include "tscore/ink_platform.h"
+#include "Continuation.h"
+#include "Processor.h"
+#include "Event.h"
+#include <atomic>
+
+#ifdef TS_MAX_THREADS_IN_EACH_THREAD_TYPE
+constexpr int MAX_THREADS_IN_EACH_TYPE = TS_MAX_THREADS_IN_EACH_THREAD_TYPE;
+#else
+constexpr int MAX_THREADS_IN_EACH_TYPE = 3071;
+#endif
+
+#ifdef TS_MAX_NUMBER_EVENT_THREADS
+constexpr int MAX_EVENT_THREADS = TS_MAX_NUMBER_EVENT_THREADS;
+#else
+constexpr int MAX_EVENT_THREADS = 4096;
+#endif
+
+class EThread;
+
+/**
+  Main processor for the Event System. The EventProcessor is the core
+  component of the Event System. Once started, it is responsible for
+  creating and managing groups of threads that execute user-defined
+  tasks asynchronously at a given time or periodically.
+
+  The EventProcessor provides a set of scheduling functions through
+  which you can specify continuations to be called back by one of its
+  threads. These function calls do not block. Instead they return an
+  Event object and schedule the callback to the continuation passed in at
+  a later or specific time, as soon as possible or at certain intervals.
+
+  Singleton model:
+
+  Every executable that imports and statically links against the
+  EventSystem library is provided with a global instance of the
+  EventProcessor called eventProcessor. Therefore, it is not necessary to
+  create instances of the EventProcessor class because it was designed
+  as a singleton. It is important to note that none of its functions
+  are reentrant.
+
+  Thread Groups (Event types):
+
+  When the EventProcessor is started, the first group of threads is spawned and it is assigned the
+  special id ET_CALL. Depending on the complexity of the state machine or protocol, you may be
+  interested in creating additional threads and the EventProcessor gives you the ability to create a
+  single thread or an entire group of threads. In the former case, you call spawn_thread and the
+  thread is independent of the thread groups and it exists as long as your continuation handle
+  executes and there are events to process. In the latter, you call @c registerEventType to get an
+  event type and then @c spawn_event_theads which creates the threads in the group of that
+  type. Such threads require events to be scheduled on a specific thread in the group or for the
+  group in general using the event type. Note that between these two calls @c
+  EThread::schedule_spawn can be used to set up per thread initialization.
+
+  Callback event codes:
+
+  @b UNIX: For all of the scheduling functions, the callback_event
+  parameter is not used. On a callback, the event code passed in to
+  the continuation handler is always EVENT_IMMEDIATE.
+
+  @b NT: The value of the event code passed in to the continuation
+  handler is the value provided in the callback_event parameter.
+
+  Event allocation policy:
+
+  Events are allocated and deallocated by the EventProcessor. A state
+  machine may access the returned, non-recurring event until it is
+  cancelled or the callback from the event is complete. For recurring
+  events, the Event may be accessed until it is cancelled. Once the event
+  is complete or cancelled, it's the eventProcessor's responsibility to
+  deallocate it.
+
+*/
+class EventProcessor : public Processor
+{
+public:
+  /** Register an event type with @a name.
+
+      This must be called to get an event type to pass to @c spawn_event_threads
+      @see spawn_event_threads
+   */
+  EventType register_event_type(char const *name);
+
+  /**
+    Spawn an additional thread for calling back the continuation. Spawns
+    a dedicated thread (EThread) that calls back the continuation passed
+    in as soon as possible.
+
+    @param cont continuation that the spawn thread will call back
+      immediately.
+    @return event object representing the start of the thread.
+
+  */
+  Event *spawn_thread(Continuation *cont, const char *thr_name, size_t stacksize = 0);
+
+  /** Spawn a group of @a n_threads event dispatching threads.
+
+      The threads run an event loop which dispatches events scheduled for a specific thread or the event type.
+
+      @return EventType or thread id for the new group of threads (@a ev_type)
+
+  */
+  EventType spawn_event_threads(EventType ev_type, int n_threads, size_t stacksize = DEFAULT_STACKSIZE);
+
+  /// Convenience overload.
+  /// This registers @a name as an event type using @c registerEventType and then calls the real @c spawn_event_threads
+  EventType spawn_event_threads(const char *name, int n_thread, size_t stacksize = DEFAULT_STACKSIZE);
+
+  /**
+    Schedules the continuation on a specific EThread to receive an event
+    at the given timeout.  Requests the EventProcessor to schedule
+    the callback to the continuation 'c' at the time specified in
+    'atimeout_at'. The event is assigned to the specified EThread.
+
+    @param c Continuation to be called back at the time specified in
+      'atimeout_at'.
+    @param atimeout_at time value at which to callback.
+    @param ethread EThread on which to schedule the event.
+    @param callback_event code to be passed back to the continuation's
+      handler. See the Remarks section.
+    @param cookie user-defined value or pointer to be passed back in
+      the Event's object cookie field.
+    @return reference to an Event object representing the scheduling
+      of this callback.
+
+  */
+  Event *schedule_imm(Continuation *c, EventType event_type = ET_CALL, int callback_event = EVENT_IMMEDIATE,
+                      void *cookie = nullptr);
+
+  /**
+    Schedules the continuation on a specific thread group to receive an
+    event at the given timeout. Requests the EventProcessor to schedule
+    the callback to the continuation 'c' at the time specified in
+    'atimeout_at'. The callback is handled by a thread in the specified
+    thread group (event_type).
+
+    @param c Continuation to be called back at the time specified in
+      'atimeout_at'.
+    @param atimeout_at Time value at which to callback.
+    @param event_type thread group id (or event type) specifying the
+      group of threads on which to schedule the callback.
+    @param callback_event code to be passed back to the continuation's
+      handler. See the Remarks section.
+    @param cookie user-defined value or pointer to be passed back in
+      the Event's object cookie field.
+    @return reference to an Event object representing the scheduling of
+      this callback.
+
+  */
+  Event *schedule_at(Continuation *c, ink_hrtime atimeout_at, EventType event_type = ET_CALL, int callback_event = EVENT_INTERVAL,
+                     void *cookie = nullptr);
+
+  /**
+    Schedules the continuation on a specific thread group to receive an
+    event after the specified timeout elapses. Requests the EventProcessor
+    to schedule the callback to the continuation 'c' after the time
+    specified in 'atimeout_in' elapses. The callback is handled by a
+    thread in the specified thread group (event_type).
+
+    @param c Continuation to call back aftert the timeout elapses.
+    @param atimeout_in amount of time after which to callback.
+    @param event_type Thread group id (or event type) specifying the
+      group of threads on which to schedule the callback.
+    @param callback_event code to be passed back to the continuation's
+      handler. See the Remarks section.
+    @param cookie user-defined value or pointer to be passed back in
+      the Event's object cookie field.
+    @return reference to an Event object representing the scheduling of
+      this callback.
+
+  */
+  Event *schedule_in(Continuation *c, ink_hrtime atimeout_in, EventType event_type = ET_CALL, int callback_event = EVENT_INTERVAL,
+                     void *cookie = nullptr);
+
+  /**
+    Schedules the continuation on a specific thread group to receive
+    an event periodically. Requests the EventProcessor to schedule the
+    callback to the continuation 'c' every time 'aperiod' elapses. The
+    callback is handled by a thread in the specified thread group
+    (event_type).
+
+    @param c Continuation to call back every time 'aperiod' elapses.
+    @param aperiod duration of the time period between callbacks.
+    @param event_type thread group id (or event type) specifying the
+      group of threads on which to schedule the callback.
+    @param callback_event code to be passed back to the continuation's
+      handler. See the Remarks section.
+    @param cookie user-defined value or pointer to be passed back in
+      the Event's object cookie field.
+    @return reference to an Event object representing the scheduling of
+      this callback.
+
+  */
+  Event *schedule_every(Continuation *c, ink_hrtime aperiod, EventType event_type = ET_CALL, int callback_event = EVENT_INTERVAL,
+                        void *cookie = nullptr);
+
+  ////////////////////////////////////////////
+  // reschedule an already scheduled event. //
+  // may be called directly or called by    //
+  // schedule_xxx Event member functions.   //
+  // The returned value may be different    //
+  // from the argument e.                   //
+  ////////////////////////////////////////////
+
+  Event *reschedule_imm(Event *e, int callback_event = EVENT_IMMEDIATE);
+  Event *reschedule_at(Event *e, ink_hrtime atimeout_at, int callback_event = EVENT_INTERVAL);
+  Event *reschedule_in(Event *e, ink_hrtime atimeout_in, int callback_event = EVENT_INTERVAL);
+  Event *reschedule_every(Event *e, ink_hrtime aperiod, int callback_event = EVENT_INTERVAL);
+
+  /// Schedule an @a event on continuation @a c when a thread of type @a ev_type is spawned.
+  /// The @a cookie is attached to the event instance passed to the continuation.
+  /// @return The scheduled event.
+  Event *schedule_spawn(Continuation *c, EventType ev_type, int event = EVENT_IMMEDIATE, void *cookie = nullptr);
+
+  /// Schedule the function @a f to be called in a thread of type @a ev_type when it is spawned.
+  Event *schedule_spawn(void (*f)(EThread *), EventType ev_type);
+
+  /// Schedule an @a event on continuation @a c to be called when a thread is spawned by this processor.
+  /// The @a cookie is attached to the event instance passed to the continuation.
+  /// @return The scheduled event.
+  //  Event *schedule_spawn(Continuation *c, int event, void *cookie = NULL);
+
+  EventProcessor();
+  ~EventProcessor() override;
+  EventProcessor(const EventProcessor &)            = delete;
+  EventProcessor &operator=(const EventProcessor &) = delete;
+
+  /**
+    Initializes the EventProcessor and its associated threads. Spawns the
+    specified number of threads, initializes their state information and
+    sets them running. It creates the initial thread group, represented
+    by the event type ET_CALL.
+
+    @return 0 if successful, and a negative value otherwise.
+
+  */
+  int start(int n_net_threads, size_t stacksize = DEFAULT_STACKSIZE) override;
+
+  /**
+    Stop the EventProcessor. Attempts to stop the EventProcessor and
+    all of the threads in each of the thread groups.
+
+  */
+  void shutdown() override;
+
+  /**
+    Allocates size bytes on the event threads. This function is thread
+    safe.
+
+    @param size bytes to be allocated.
+
+  */
+  off_t allocate(int size);
+
+  /**
+    An array of pointers to all of the EThreads handled by the
+    EventProcessor. An array of pointers to all of the EThreads created
+    throughout the existence of the EventProcessor instance.
+
+  */
+  EThread *all_ethreads[MAX_EVENT_THREADS];
+
+  /// Data kept for each thread group.
+  /// The thread group ID is the index into an array of these and so is not stored explicitly.
+  struct ThreadGroupDescriptor {
+    std::string _name;                               ///< Name for the thread group.
+    int _count                 = 0;                  ///< # of threads of this type.
+    std::atomic<int> _started  = 0;                  ///< # of started threads of this type.
+    uint64_t _next_round_robin = 0;                  ///< Index of thread to use for events assigned to this group.
+    Que(Event, link) _spawnQueue;                    ///< Events to dispatch when thread is spawned.
+    EThread *_thread[MAX_THREADS_IN_EACH_TYPE] = {}; ///< The actual threads in this group.
+    std::function<void()> _afterStartCallback  = nullptr;
+  };
+
+  /// Storage for per group data.
+  ThreadGroupDescriptor thread_group[MAX_EVENT_TYPES];
+
+  /// Number of defined thread groups.
+  int n_thread_groups = 0;
+
+  /**
+    Total number of threads controlled by this EventProcessor.  This is
+    the count of all the EThreads spawn by this EventProcessor, excluding
+    those created by spawn_thread
+
+  */
+  int n_ethreads = 0;
+
+  bool has_tg_started(int etype);
+
+  /*------------------------------------------------------*\
+  | Unix & non NT Interface                                |
+  \*------------------------------------------------------*/
+
+  Event *schedule(Event *e, EventType etype);
+  EThread *assign_thread(EventType etype);
+  EThread *assign_affinity_by_type(Continuation *cont, EventType etype);
+
+  EThread *all_dthreads[MAX_EVENT_THREADS];
+  int n_dthreads       = 0; // No. of dedicated threads
+  int thread_data_used = 0;
+
+  /// Provide container style access to just the active threads, not the entire array.
+  class active_threads_type
+  {
+    using iterator = EThread *const *; ///< Internal iterator type, pointer to array element.
+  public:
+    iterator
+    begin() const
+    {
+      return _begin;
+    }
+
+    iterator
+    end() const
+    {
+      return _end;
+    }
+
+  private:
+    iterator _begin; ///< Start of threads.
+    iterator _end;   ///< End of threads.
+    /// Construct from base of the array (@a start) and the current valid count (@a n).
+    active_threads_type(iterator start, int n) : _begin(start), _end(start + n) {}
+    friend class EventProcessor;
+  };
+
+  // These can be used in container for loops and other range operations.
+  active_threads_type
+  active_ethreads() const
+  {
+    return {all_ethreads, n_ethreads};
+  }
+
+  active_threads_type
+  active_dthreads() const
+  {
+    return {all_dthreads, n_dthreads};
+  }
+
+  active_threads_type
+  active_group_threads(int type) const
+  {
+    ThreadGroupDescriptor const &group{thread_group[type]};
+    return {group._thread, group._count};
+  }
+
+private:
+  void initThreadState(EThread *);
+
+  /// Used to generate a callback at the start of thread execution.
+  class ThreadInit : public Continuation
+  {
+    using self = ThreadInit;
+    EventProcessor *_evp;
+
+  public:
+    explicit ThreadInit(EventProcessor *evp) : _evp(evp) { SET_HANDLER(&self::init); }
+
+    int
+    init(int /* event ATS_UNUSED */, Event *ev)
+    {
+      _evp->initThreadState(ev->ethread);
+      return 0;
+    }
+  };
+  friend class ThreadInit;
+  ThreadInit thread_initializer;
+
+  // Lock write access to the dedicated thread vector.
+  // @internal Not a @c ProxyMutex - that's a whole can of problems due to initialization ordering.
+  ink_mutex dedicated_thread_spawn_mutex;
+};
+
+extern class EventProcessor eventProcessor;
+
+void thread_started(EThread *);
diff --git a/include/iocore/eventsystem/EventSystem.h b/include/iocore/eventsystem/EventSystem.h
new file mode 100644
index 0000000000..63144a293d
--- /dev/null
+++ b/include/iocore/eventsystem/EventSystem.h
@@ -0,0 +1,51 @@
+/** @file
+
+  Event subsystem
+
+  @section license License
+
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+ */
+
+#pragma once
+#define _I_EventSystem_h
+
+#include "tscore/ink_platform.h"
+#include "ts/apidefs.h"
+
+#include "IOBuffer.h"
+#include "Action.h"
+#include "Continuation.h"
+#include "EThread.h"
+#include "Event.h"
+#include "EventProcessor.h"
+
+#include "Lock.h"
+#include "PriorityEventQueue.h"
+#include "Processor.h"
+#include "ProtectedQueue.h"
+#include "Thread.h"
+#include "VIO.h"
+#include "VConnection.h"
+#include "records/RecProcess.h"
+#include "SocketManager.h"
+#include "RecProcess.h"
+
+static constexpr ts::ModuleVersion EVENT_SYSTEM_MODULE_PUBLIC_VERSION(1, 0, ts::ModuleVersion::PUBLIC);
+
+void ink_event_system_init(ts::ModuleVersion version);
diff --git a/iocore/eventsystem/I_IOBuffer.h b/include/iocore/eventsystem/IOBuffer.h
similarity index 100%
rename from iocore/eventsystem/I_IOBuffer.h
rename to include/iocore/eventsystem/IOBuffer.h
diff --git a/include/iocore/eventsystem/Lock.h b/include/iocore/eventsystem/Lock.h
new file mode 100644
index 0000000000..61edd616bf
--- /dev/null
+++ b/include/iocore/eventsystem/Lock.h
@@ -0,0 +1,681 @@
+/** @file
+
+  Basic locks for threads
+
+  @section license License
+
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ */
+
+#pragma once
+
+#include "tscore/ink_platform.h"
+#include "tscore/Diags.h"
+#include "Thread.h"
+
+#define MAX_LOCK_TIME               HRTIME_MSECONDS(200)
+#define THREAD_MUTEX_THREAD_HOLDING (-1024 * 1024)
+
+/*------------------------------------------------------*\
+|  Macros                                                |
+\*------------------------------------------------------*/
+
+/**
+  Blocks until the lock to the ProxyMutex is acquired.
+
+  This macro performs a blocking call until the lock to the ProxyMutex
+  is acquired. This call allocates a special object that holds the
+  lock to the ProxyMutex only for the scope of the function or
+  region. It is a good practice to delimit such scope explicitly
+  with '&#123;' and '&#125;'.
+
+  @param _l Arbitrary name for the lock to use in this call
+  @param _m A pointer to (or address of) a ProxyMutex object
+  @param _t The current EThread executing your code.
+
+*/
+
+// A weak version of the SCOPED_MUTEX_LOCK macro, allows the mutex to be a nullptr.
+#ifdef DEBUG
+#define WEAK_SCOPED_MUTEX_LOCK(_l, _m, _t) WeakMutexLock _l(MakeSourceLocation(), (char *)nullptr, _m, _t);
+#else // DEBUG
+#define WEAK_SCOPED_MUTEX_LOCK(_l, _m, _t) WeakMutexLock _l(_m, _t);
+#endif // DEBUG
+
+#ifdef DEBUG
+#define SCOPED_MUTEX_LOCK(_l, _m, _t) MutexLock _l(MakeSourceLocation(), (char *)nullptr, _m, _t)
+#else // DEBUG
+#define SCOPED_MUTEX_LOCK(_l, _m, _t) MutexLock _l(_m, _t)
+#endif // DEBUG
+
+/**
+  Attempts to acquire the lock to the ProxyMutex.
+
+  This macro attempts to acquire the lock to the specified ProxyMutex
+  object in a non-blocking manner. After using the macro you can
+  see if it was successful by comparing the lock variable with true
+  or false (the variable name passed in the _l parameter).
+
+  @param _l Arbitrary name for the lock to use in this call (lock variable)
+  @param _m A pointer to (or address of) a ProxyMutex object
+  @param _t The current EThread executing your code.
+
+*/
+
+#ifdef DEBUG
+#define WEAK_MUTEX_TRY_LOCK(_l, _m, _t) WeakMutexTryLock _l(MakeSourceLocation(), (char *)nullptr, _m, _t);
+#else // DEBUG
+#define WEAK_MUTEX_TRY_LOCK(_l, _m, _t) WeakMutexTryLock _l(_m, _t);
+#endif // DEBUG
+
+#ifdef DEBUG
+#define MUTEX_TRY_LOCK(_l, _m, _t) MutexTryLock _l(MakeSourceLocation(), (char *)nullptr, _m, _t)
+#else // DEBUG
+#define MUTEX_TRY_LOCK(_l, _m, _t) MutexTryLock _l(_m, _t)
+#endif // DEBUG
+
+/**
+  Releases the lock on a ProxyMutex.
+
+  This macro releases the lock on the ProxyMutex, provided it is
+  currently held. The lock must have been successfully acquired
+  with one of the MUTEX macros.
+
+  @param _l Arbitrary name for the lock to use in this call (lock
+    variable) It must be the same name as the one used to acquire the
+    lock.
+
+*/
+#define MUTEX_RELEASE(_l) (_l).release()
+
+/////////////////////////////////////
+// DEPRECATED DEPRECATED DEPRECATED
+#ifdef DEBUG
+#define MUTEX_TAKE_TRY_LOCK(_m, _t) Mutex_trylock(MakeSourceLocation(), (char *)nullptr, _m, _t)
+#else
+#define MUTEX_TAKE_TRY_LOCK(_m, _t) Mutex_trylock(_m, _t)
+#endif
+
+#ifdef DEBUG
+#define MUTEX_TAKE_LOCK(_m, _t)         Mutex_lock(MakeSourceLocation(), (char *)nullptr, _m, _t)
+#define MUTEX_TAKE_LOCK_FOR(_m, _t, _c) Mutex_lock(MakeSourceLocation(), nullptr, _m, _t)
+#else
+#define MUTEX_TAKE_LOCK(_m, _t)         Mutex_lock(_m, _t)
+#define MUTEX_TAKE_LOCK_FOR(_m, _t, _c) Mutex_lock(_m, _t)
+#endif // DEBUG
+
+#define MUTEX_UNTAKE_LOCK(_m, _t) Mutex_unlock(_m, _t)
+// DEPRECATED DEPRECATED DEPRECATED
+/////////////////////////////////////
+
+class EThread;
+using EThreadPtr = EThread *;
+
+#if DEBUG
+extern void lock_waiting(const SourceLocation &, const char *handler);
+extern void lock_holding(const SourceLocation &, const char *handler);
+extern void lock_taken(const SourceLocation &, const char *handler);
+#endif
+
+/**
+  Lock object used in continuations and threads.
+
+  The ProxyMutex class is the main synchronization object used
+  throughout the Event System. It is a reference counted object
+  that provides mutually exclusive access to a resource. Since the
+  Event System is multithreaded by design, the ProxyMutex is required
+  to protect data structures and state information that could
+  otherwise be affected by the action of concurrent threads.
+
+  A ProxyMutex object has an ink_mutex member (defined in ink_mutex.h)
+  which is a wrapper around the platform dependent mutex type. This
+  member allows the ProxyMutex to provide the functionality required
+  by the users of the class without the burden of platform specific
+  function calls.
+
+  The ProxyMutex also has a reference to the current EThread holding
+  the lock as a back pointer for verifying that it is released
+  correctly.
+
+  Acquiring/Releasing locks:
+
+  Included with the ProxyMutex class, there are several macros that
+  allow you to lock/unlock the underlying mutex object.
+
+*/
+class ProxyMutex : public RefCountObj
+{
+public:
+  /**
+    Underlying mutex object.
+
+    The platform independent mutex for the ProxyMutex class. You
+    must not modify or set it directly.
+
+  */
+  // coverity[uninit_member]
+  ink_mutex the_mutex;
+
+  /**
+    Backpointer to owning thread.
+
+    This is a pointer to the thread currently holding the mutex
+    lock.  You must not modify or set this value directly.
+
+  */
+  EThreadPtr thread_holding;
+
+  int nthread_holding;
+
+#ifdef DEBUG
+  ink_hrtime hold_time;
+  SourceLocation srcloc;
+  const char *handler;
+
+#ifdef MAX_LOCK_TAKEN
+  int taken;
+#endif // MAX_LOCK_TAKEN
+
+#ifdef LOCK_CONTENTION_PROFILING
+  int total_acquires, blocking_acquires, nonblocking_acquires, successful_nonblocking_acquires, unsuccessful_nonblocking_acquires;
+  void print_lock_stats(int flag);
+#endif // LOCK_CONTENTION_PROFILING
+#endif // DEBUG
+  void free() override;
+
+  /**
+    Constructor - use new_ProxyMutex() instead.
+
+    The constructor of a ProxyMutex object. Initializes the state
+    of the object but leaves the initialization of the mutex member
+    until it is needed (through init()). Do not use this constructor,
+    the preferred mechanism for creating a ProxyMutex is via the
+    new_ProxyMutex function, which provides a faster allocation.
+
+  */
+  ProxyMutex()
+#ifdef DEBUG
+    : srcloc(nullptr, nullptr, 0)
+#endif
+  {
+    thread_holding  = nullptr;
+    nthread_holding = 0;
+#ifdef DEBUG
+    hold_time = 0;
+    handler   = nullptr;
+#ifdef MAX_LOCK_TAKEN
+    taken = 0;
+#endif // MAX_LOCK_TAKEN
+#ifdef LOCK_CONTENTION_PROFILING
+    total_acquires                    = 0;
+    blocking_acquires                 = 0;
+    nonblocking_acquires              = 0;
+    successful_nonblocking_acquires   = 0;
+    unsuccessful_nonblocking_acquires = 0;
+#endif // LOCK_CONTENTION_PROFILING
+#endif // DEBUG
+    // coverity[uninit_member]
+  }
+
+  /**
+    Initializes the underlying mutex object.
+
+    After constructing your ProxyMutex object, use this function
+    to initialize the underlying mutex object with an optional name.
+
+    @param name Name to identify this ProxyMutex. Its use depends
+      on the given platform.
+
+  */
+  void
+  init(const char *name = "UnnamedMutex")
+  {
+    ink_mutex_init(&the_mutex);
+  }
+};
+
+// The ClassAllocator for ProxyMutexes
+extern ClassAllocator<ProxyMutex> mutexAllocator;
+
+inline bool
+Mutex_trylock(
+#ifdef DEBUG
+  const SourceLocation &location, const char *ahandler,
+#endif
+  ProxyMutex *m, EThread *t)
+{
+  ink_assert(t != nullptr);
+  ink_assert(t == reinterpret_cast<EThread *>(this_thread()));
+  if (m->thread_holding != t) {
+    if (!ink_mutex_try_acquire(&m->the_mutex)) {
+#ifdef DEBUG
+      lock_waiting(m->srcloc, m->handler);
+#ifdef LOCK_CONTENTION_PROFILING
+      m->unsuccessful_nonblocking_acquires++;
+      m->nonblocking_acquires++;
+      m->total_acquires++;
+      m->print_lock_stats(0);
+#endif // LOCK_CONTENTION_PROFILING
+#endif // DEBUG
+      return false;
+    }
+    m->thread_holding = t;
+#ifdef DEBUG
+    m->srcloc    = location;
+    m->handler   = ahandler;
+    m->hold_time = ink_get_hrtime();
+#ifdef MAX_LOCK_TAKEN
+    m->taken++;
+#endif // MAX_LOCK_TAKEN
+#endif // DEBUG
+  }
+#ifdef DEBUG
+#ifdef LOCK_CONTENTION_PROFILING
+  m->successful_nonblocking_acquires++;
+  m->nonblocking_acquires++;
+  m->total_acquires++;
+  m->print_lock_stats(0);
+#endif // LOCK_CONTENTION_PROFILING
+#endif // DEBUG
+  m->nthread_holding++;
+  return true;
+}
+
+inline bool
+Mutex_trylock(
+#ifdef DEBUG
+  const SourceLocation &location, const char *ahandler,
+#endif
+  Ptr<ProxyMutex> &m, EThread *t)
+{
+  return Mutex_trylock(
+#ifdef DEBUG
+    location, ahandler,
+#endif
+    m.get(), t);
+}
+
+inline int
+Mutex_lock(
+#ifdef DEBUG
+  const SourceLocation &location, const char *ahandler,
+#endif
+  ProxyMutex *m, EThread *t)
+{
+  ink_assert(t != nullptr);
+  if (m->thread_holding != t) {
+    ink_mutex_acquire(&m->the_mutex);
+    m->thread_holding = t;
+    ink_assert(m->thread_holding);
+#ifdef DEBUG
+    m->srcloc    = location;
+    m->handler   = ahandler;
+    m->hold_time = ink_get_hrtime();
+#ifdef MAX_LOCK_TAKEN
+    m->taken++;
+#endif // MAX_LOCK_TAKEN
+#endif // DEBUG
+  }
+#ifdef DEBUG
+#ifdef LOCK_CONTENTION_PROFILING
+  m->blocking_acquires++;
+  m->total_acquires++;
+  m->print_lock_stats(0);
+#endif // LOCK_CONTENTION_PROFILING
+#endif // DEBUG
+  m->nthread_holding++;
+  return true;
+}
+
+inline int
+Mutex_lock(
+#ifdef DEBUG
+  const SourceLocation &location, const char *ahandler,
+#endif
+  Ptr<ProxyMutex> &m, EThread *t)
+{
+  return Mutex_lock(
+#ifdef DEBUG
+    location, ahandler,
+#endif
+    m.get(), t);
+}
+
+inline void
+Mutex_unlock(ProxyMutex *m, EThread *t)
+{
+  if (m->nthread_holding) {
+    ink_assert(t == m->thread_holding);
+    m->nthread_holding--;
+    if (!m->nthread_holding) {
+#ifdef DEBUG
+      if (ink_get_hrtime() - m->hold_time > MAX_LOCK_TIME)
+        lock_holding(m->srcloc, m->handler);
+#ifdef MAX_LOCK_TAKEN
+      if (m->taken > MAX_LOCK_TAKEN)
+        lock_taken(m->srcloc, m->handler);
+#endif // MAX_LOCK_TAKEN
+      m->srcloc  = SourceLocation(nullptr, nullptr, 0);
+      m->handler = nullptr;
+#endif // DEBUG
+      ink_assert(m->thread_holding);
+      m->thread_holding = nullptr;
+      ink_mutex_release(&m->the_mutex);
+    }
+  }
+}
+
+inline void
+Mutex_unlock(Ptr<ProxyMutex> &m, EThread *t)
+{
+  Mutex_unlock(m.get(), t);
+}
+
+class WeakMutexLock
+{
+private:
+  Ptr<ProxyMutex> m;
+  bool locked_p{false};
+
+public:
+  WeakMutexLock() = default;
+
+  WeakMutexLock(
+#ifdef DEBUG
+    const SourceLocation &location, const char *ahandler,
+#endif // DEBUG
+    Ptr<ProxyMutex> &am, EThread *t)
+    : m(am), locked_p(true)
+  {
+    if (m.get()) {
+      Mutex_lock(
+#ifdef DEBUG
+        location, ahandler,
+#endif // DEBUG
+        m, t);
+    }
+  }
+
+  WeakMutexLock(WeakMutexLock &)                  = delete;
+  WeakMutexLock &operator=(const WeakMutexLock &) = delete;
+  WeakMutexLock(WeakMutexLock &&)                 = delete;
+
+  WeakMutexLock &
+  operator=(WeakMutexLock &&orig)
+  {
+    if (&orig != this) {
+      std::swap(m, orig.m);
+      std::swap(locked_p, orig.locked_p);
+    }
+    return *this;
+  }
+
+  void
+  release()
+  {
+    if (locked_p && m.get()) {
+      Mutex_unlock(m, m->thread_holding);
+    }
+    locked_p = false;
+  }
+
+  ~WeakMutexLock() { this->release(); }
+};
+
+/** Scoped lock class for ProxyMutex
+ */
+class MutexLock
+{
+private:
+  Ptr<ProxyMutex> m{};
+  bool locked_p{false};
+
+public:
+  MutexLock() = default;
+
+  MutexLock(
+#ifdef DEBUG
+    const SourceLocation &location, const char *ahandler,
+#endif // DEBUG
+    Ptr<ProxyMutex> &am, EThread *t)
+    : m(am), locked_p(true)
+  {
+    Mutex_lock(
+#ifdef DEBUG
+      location, ahandler,
+#endif // DEBUG
+      m, t);
+  }
+
+  MutexLock(MutexLock &)                  = delete;
+  MutexLock &operator=(const MutexLock &) = delete;
+  MutexLock(MutexLock &&)                 = delete;
+
+  MutexLock &
+  operator=(MutexLock &&orig)
+  {
+    if (&orig != this) {
+      std::swap(m, orig.m);
+      std::swap(locked_p, orig.locked_p);
+    }
+    return *this;
+  }
+
+  void
+  release()
+  {
+    if (locked_p) {
+      Mutex_unlock(m, m->thread_holding);
+    }
+    locked_p = false;
+  }
+
+  ~MutexLock() { this->release(); }
+};
+
+/** Scoped try lock class for ProxyMutex
+ */
+class WeakMutexTryLock
+{
+private:
+  Ptr<ProxyMutex> m;
+  bool lock_acquired{false};
+
+public:
+  WeakMutexTryLock() = default;
+
+  WeakMutexTryLock(
+#ifdef DEBUG
+    const SourceLocation &location, const char *ahandler,
+#endif // DEBUG
+    Ptr<ProxyMutex> &am, EThread *t)
+    : m(am)
+  {
+    if (m.get()) {
+      lock_acquired = Mutex_trylock(
+#ifdef DEBUG
+        location, ahandler,
+#endif // DEBUG
+        m, t);
+    } else {
+      lock_acquired = true;
+    }
+  }
+
+  WeakMutexTryLock(WeakMutexTryLock &)                  = delete;
+  WeakMutexTryLock &operator=(const WeakMutexTryLock &) = delete;
+  WeakMutexTryLock(WeakMutexTryLock &&)                 = delete;
+
+  WeakMutexTryLock &
+  operator=(WeakMutexTryLock &&orig)
+  {
+    if (&orig != this) {
+      std::swap(m, orig.m);
+      std::swap(lock_acquired, orig.lock_acquired);
+    }
+    return *this;
+  }
+
+  ~WeakMutexTryLock()
+  {
+    if (lock_acquired && m.get()) {
+      Mutex_unlock(m, m->thread_holding);
+    }
+    lock_acquired = false;
+  }
+
+  /** Spin till lock is acquired
+   */
+  void
+  acquire(EThread *t)
+  {
+    lock_acquired = true;
+    if (m.get()) {
+      MUTEX_TAKE_LOCK(m, t);
+    }
+  }
+
+  void
+  release()
+  {
+    if (lock_acquired && m.get()) {
+      Mutex_unlock(m, m->thread_holding);
+    }
+    lock_acquired = false;
+  }
+
+  bool
+  is_locked() const
+  {
+    return lock_acquired;
+  }
+
+  const ProxyMutex *
+  get_mutex() const
+  {
+    return m.get();
+  }
+};
+
+/** Scoped try lock class for ProxyMutex
+ */
+class MutexTryLock
+{
+private:
+  Ptr<ProxyMutex> m;
+  bool lock_acquired{false};
+
+public:
+  MutexTryLock() = default;
+
+  MutexTryLock(
+#ifdef DEBUG
+    const SourceLocation &location, const char *ahandler,
+#endif // DEBUG
+    Ptr<ProxyMutex> &am, EThread *t)
+    : m(am)
+  {
+    lock_acquired = Mutex_trylock(
+#ifdef DEBUG
+      location, ahandler,
+#endif // DEBUG
+      m, t);
+  }
+
+  MutexTryLock(MutexTryLock &)                  = delete;
+  MutexTryLock &operator=(const MutexTryLock &) = delete;
+  MutexTryLock(MutexTryLock &&)                 = delete;
+
+  MutexTryLock &
+  operator=(MutexTryLock &&orig)
+  {
+    if (&orig != this) {
+      std::swap(m, orig.m);
+      std::swap(lock_acquired, orig.lock_acquired);
+    }
+    return *this;
+  }
+
+  ~MutexTryLock()
+  {
+    if (lock_acquired) {
+      Mutex_unlock(m, m->thread_holding);
+    }
+  }
+
+  /** Spin till lock is acquired
+   */
+  void
+  acquire(EThread *t)
+  {
+    MUTEX_TAKE_LOCK(m, t);
+    lock_acquired = true;
+  }
+
+  void
+  release()
+  {
+    if (lock_acquired) {
+      Mutex_unlock(m, m->thread_holding);
+    }
+    lock_acquired = false;
+  }
+
+  bool
+  is_locked() const
+  {
+    return lock_acquired;
+  }
+
+  const ProxyMutex *
+  get_mutex() const
+  {
+    return m.get();
+  }
+};
+
+inline void
+ProxyMutex::free()
+{
+#ifdef DEBUG
+#ifdef LOCK_CONTENTION_PROFILING
+  print_lock_stats(1);
+#endif
+#endif
+  ink_mutex_destroy(&the_mutex);
+  mutexAllocator.free(this);
+}
+
+// TODO should take optional mutex "name" identifier, to pass along to the init() fun
+/**
+  Creates a new ProxyMutex object.
+
+  This is the preferred mechanism for constructing objects of the
+  ProxyMutex class. It provides you with faster allocation than
+  that of the normal constructor.
+
+  @return A pointer to a ProxyMutex object appropriate for the build
+    environment.
+
+*/
+inline ProxyMutex *
+new_ProxyMutex()
+{
+  ProxyMutex *m = mutexAllocator.alloc();
+  m->init();
+  return m;
+}
diff --git a/include/iocore/eventsystem/MIOBufferWriter.h b/include/iocore/eventsystem/MIOBufferWriter.h
new file mode 100644
index 0000000000..5aa47e2597
--- /dev/null
+++ b/include/iocore/eventsystem/MIOBufferWriter.h
@@ -0,0 +1,189 @@
+/** @file
+
+    Buffer Writer for an MIOBuffer.
+
+    @section license License
+
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+ */
+
+#pragma once
+
+#include <cstring>
+#include <iosfwd>
+
+#include "tscore/ink_assert.h"
+
+#if defined(UNIT_TEST_BUFFER_WRITER)
+#undef ink_assert
+#define ink_assert ink_release_assert
+#endif
+
+#include "tscpp/util/ts_bw.h"
+
+#if !defined(UNIT_TEST_BUFFER_WRITER)
+#include "IOBuffer.h"
+#endif
+
+/** BufferWriter interface on top of IOBuffer blocks.
+
+    @internal This should be changed to IOBufferChain once I port that to open source.
+ */
+class MIOBufferWriter : public swoc::BufferWriter
+{
+  using self_type  = MIOBufferWriter; ///< Self reference type.
+  using super_type = swoc::BufferWriter;
+
+public:
+  explicit MIOBufferWriter(MIOBuffer *miob) : _miob(miob) {}
+
+  using super_type::write;
+
+  self_type &write(const void *data_, size_t length) override;
+
+  self_type &
+  write(char c) override
+  {
+    return this->write(&c, 1);
+  }
+
+  bool
+  error() const override
+  {
+    return false;
+  }
+
+  char *
+  aux_data() override
+  {
+    IOBufferBlock *iobbPtr = _miob->first_write_block();
+
+    if (!iobbPtr) {
+      return nullptr;
+    }
+
+    return iobbPtr->end();
+  }
+
+  size_t
+  remaining() const
+  {
+    if (IOBufferBlock *iobbPtr = _miob->first_write_block(); iobbPtr) {
+      return iobbPtr->write_avail();
+    }
+    return 0;
+  }
+
+  swoc::MemSpan<char>
+  aux_span()
+  {
+    if (IOBufferBlock *iobbPtr = _miob->first_write_block(); iobbPtr) {
+      return {iobbPtr->end(), size_t(iobbPtr->write_avail())};
+    }
+    return {};
+  }
+
+  // Write the first n characters that have been placed in the auxiliary buffer.  This call invalidates the auxiliary buffer.
+  // This function should not be called if no auxiliary buffer is available.
+  //
+  bool
+  commit(size_t n) override
+  {
+    if (n) {
+      IOBufferBlock *iobbPtr = _miob->first_write_block();
+
+      ink_assert(iobbPtr and (n <= size_t(iobbPtr->write_avail())));
+
+      iobbPtr->fill(n);
+
+      _numWritten += n;
+    }
+
+    return true;
+  }
+
+  // No fixed limit on capacity.
+  //
+  size_t
+  capacity() const override
+  {
+    return (~size_t(0));
+  }
+
+  size_t
+  extent() const override
+  {
+    return _numWritten;
+  }
+
+  // Not useful in this derived class.
+  //
+  self_type &restrict(size_t) override { return *this; }
+
+  // Not useful in this derived class.
+  //
+  self_type &
+  restore(size_t) override
+  {
+    return *this;
+  }
+
+  // This must not be called for this derived class.
+  const char *
+  data() const override
+  {
+    ink_assert(false);
+    return nullptr;
+  }
+
+  // This must not be called for this derived class.
+  self_type &
+  discard(size_t) override
+  {
+    ink_assert(false);
+    return *this;
+  }
+
+  // This must not be called for this derived class.
+  self_type &
+  copy(size_t, size_t, size_t) override
+  {
+    ink_assert(false);
+    return *this;
+  }
+
+  /// Output the buffer contents to the @a stream.
+  /// @return The destination stream.
+  std::ostream &operator>>(std::ostream &stream) const override;
+  /// Output the buffer contents to the file for file descriptor @a fd.
+  /// @return The number of bytes written.
+  ssize_t operator>>(int fd) const;
+
+protected:
+  MIOBuffer *_miob;
+
+private:
+  size_t _numWritten = 0;
+
+  virtual void
+  addBlock()
+  {
+    _miob->add_block();
+  }
+  // INTERNAL - Overload removed, make sure it's not used.
+  self_type &write(size_t n);
+};
diff --git a/include/iocore/eventsystem/PriorityEventQueue.h b/include/iocore/eventsystem/PriorityEventQueue.h
new file mode 100644
index 0000000000..505e0a0e7e
--- /dev/null
+++ b/include/iocore/eventsystem/PriorityEventQueue.h
@@ -0,0 +1,122 @@
+/** @file
+
+  Queue of Events sorted by the "at_timeout" field
+
+  @section license License
+
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ */
+
+#pragma once
+
+#include "tscore/ink_platform.h"
+#include "Event.h"
+
+// <5ms, 10, 20, 40, 80, 160, 320, 640, 1280, 2560, 5120
+#define N_PQ_LIST          10
+#define PQ_BUCKET_TIME(_i) (HRTIME_MSECONDS(5) << (_i))
+
+class EThread;
+
+struct PriorityEventQueue {
+  Que(Event, link) after[N_PQ_LIST];
+  ink_hrtime last_check_time;
+  uint32_t last_check_buckets;
+
+  void
+  enqueue(Event *e, ink_hrtime now)
+  {
+    ink_hrtime t = e->timeout_at - now;
+    int i        = 0;
+    // equivalent but faster
+    if (t <= PQ_BUCKET_TIME(3)) {
+      if (t <= PQ_BUCKET_TIME(1)) {
+        if (t <= PQ_BUCKET_TIME(0)) {
+          i = 0;
+        } else {
+          i = 1;
+        }
+      } else {
+        if (t <= PQ_BUCKET_TIME(2)) {
+          i = 2;
+        } else {
+          i = 3;
+        }
+      }
+    } else {
+      if (t <= PQ_BUCKET_TIME(7)) {
+        if (t <= PQ_BUCKET_TIME(5)) {
+          if (t <= PQ_BUCKET_TIME(4)) {
+            i = 4;
+          } else {
+            i = 5;
+          }
+        } else {
+          if (t <= PQ_BUCKET_TIME(6)) {
+            i = 6;
+          } else {
+            i = 7;
+          }
+        }
+      } else {
+        if (t <= PQ_BUCKET_TIME(8)) {
+          i = 8;
+        } else {
+          i = 9;
+        }
+      }
+    }
+    e->in_the_priority_queue = 1;
+    e->in_heap               = i;
+    after[i].enqueue(e);
+  }
+
+  void
+  remove(Event *e)
+  {
+    ink_assert(e->in_the_priority_queue);
+    e->in_the_priority_queue = 0;
+    after[e->in_heap].remove(e);
+  }
+
+  Event *
+  dequeue_ready(ink_hrtime t)
+  {
+    (void)t;
+    Event *e = after[0].dequeue();
+    if (e) {
+      ink_assert(e->in_the_priority_queue);
+      e->in_the_priority_queue = 0;
+    }
+    return e;
+  }
+
+  void check_ready(ink_hrtime now, EThread *t);
+
+  ink_hrtime
+  earliest_timeout()
+  {
+    for (int i = 0; i < N_PQ_LIST; i++) {
+      if (after[i].head) {
+        return last_check_time + (PQ_BUCKET_TIME(i) / 2);
+      }
+    }
+    return last_check_time + HRTIME_FOREVER;
+  }
+
+  PriorityEventQueue();
+};
diff --git a/iocore/eventsystem/I_Processor.h b/include/iocore/eventsystem/Processor.h
similarity index 100%
rename from iocore/eventsystem/I_Processor.h
rename to include/iocore/eventsystem/Processor.h
diff --git a/include/iocore/eventsystem/ProtectedQueue.h b/include/iocore/eventsystem/ProtectedQueue.h
new file mode 100644
index 0000000000..1c971faf4c
--- /dev/null
+++ b/include/iocore/eventsystem/ProtectedQueue.h
@@ -0,0 +1,54 @@
+/** @file
+
+  A brief file description
+
+  @section license License
+
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ */
+
+/****************************************************************************
+
+  Protected Queue, a FIFO queue with the following functionality:
+  (1). Multiple threads could be simultaneously trying to enqueue
+       and dequeue. Hence the queue needs to be protected with mutex.
+  (2). In case the queue is empty, dequeue() sleeps for a specified
+       amount of time, or until a new element is inserted, whichever
+       is earlier
+
+
+ ****************************************************************************/
+#pragma once
+
+#include "tscore/ink_platform.h"
+#include "Event.h"
+struct ProtectedQueue {
+  void enqueue(Event *e);
+  void signal();
+  int try_signal();             // Use non blocking lock and if acquired, signal
+  void enqueue_local(Event *e); // Safe when called from the same thread
+  Event *dequeue_local();
+  void dequeue_external();       // Dequeue any external events.
+  void wait(ink_hrtime timeout); // Wait for @a timeout nanoseconds on a condition variable if there are no events.
+
+  InkAtomicList al;
+  ink_mutex lock;
+  ink_cond might_have_data;
+  Que(Event, link) localQueue;
+
+  ProtectedQueue();
+};
diff --git a/iocore/eventsystem/I_ProxyAllocator.h b/include/iocore/eventsystem/ProxyAllocator.h
similarity index 100%
rename from iocore/eventsystem/I_ProxyAllocator.h
rename to include/iocore/eventsystem/ProxyAllocator.h
diff --git a/include/iocore/eventsystem/RecProcess.h b/include/iocore/eventsystem/RecProcess.h
new file mode 100644
index 0000000000..59b04e508b
--- /dev/null
+++ b/include/iocore/eventsystem/RecProcess.h
@@ -0,0 +1,40 @@
+/** @file
+
+Public RecProcess declarations
+
+  @section license License
+
+    Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ */
+
+#pragma once
+
+#include "records/RecDefs.h"
+#include "tscore/Diags.h"
+
+//-------------------------------------------------------------------------
+// Initialization/Starting
+//-------------------------------------------------------------------------
+int RecProcessInit(Diags *diags = nullptr);
+int RecProcessStart();
+
+//-------------------------------------------------------------------------
+// Setters for manipulating internal sleep intervals
+//-------------------------------------------------------------------------
+void RecProcess_set_raw_stat_sync_interval_ms(int ms);
+void RecProcess_set_config_update_interval_ms(int ms);
+void RecProcess_set_remote_sync_interval_ms(int ms);
diff --git a/iocore/eventsystem/I_SocketManager.h b/include/iocore/eventsystem/SocketManager.h
similarity index 100%
rename from iocore/eventsystem/I_SocketManager.h
rename to include/iocore/eventsystem/SocketManager.h
diff --git a/include/iocore/eventsystem/Tasks.h b/include/iocore/eventsystem/Tasks.h
new file mode 100644
index 0000000000..84ff2515ca
--- /dev/null
+++ b/include/iocore/eventsystem/Tasks.h
@@ -0,0 +1,38 @@
+/** @file
+
+  A brief file description
+
+  @section license License
+
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+ */
+
+#pragma once
+
+#include "EventSystem.h"
+
+extern EventType ET_TASK;
+
+class TasksProcessor : public Processor
+{
+public:
+  EventType register_event_type();
+  int start(int task_threads, size_t stacksize = DEFAULT_STACKSIZE) override;
+};
+
+extern TasksProcessor tasksProcessor;
diff --git a/include/iocore/eventsystem/Thread.h b/include/iocore/eventsystem/Thread.h
new file mode 100644
index 0000000000..97d427ab08
--- /dev/null
+++ b/include/iocore/eventsystem/Thread.h
@@ -0,0 +1,170 @@
+/** @file
+
+  Thread
+
+  @section license License
+
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  @section details Details
+
+  Thread class provides the basic functionality for threads. Typically,
+  there will be additional derived classes. Having a common base class
+  for all threads is useful in many cases. I discuss below the use of
+  Threads in the context of Event Subsystem. Hopefully this would be
+  typical of other situations.
+
+  EventProcessor needs to create a bunch of threads. It declares a
+  class called EThread, derived from Thread. It is the responsibility of
+  the EventProcessor to create and manage all the threads needed in the
+  Event Subsystem (Note: we have removed the original ThreadManager class
+  which used to create and manage *all* the threads in the system). By
+  monitoring, we mean checking the heartbeat of each thread and the
+  number of threads in the system etc.
+
+  A derived class should either provide the function (and arguments)
+  needed by the Thread class (see start()), or should define the virtual
+  function execute().
+
+  The Thread class maintains a thread_key which registers *all*
+  the threads in the system (that have been created using Thread or
+  a derived class), using thread specific data calls.  Whenever, you
+  call this_thread() you get a pointer to the Thread that is currently
+  executing you.  Additionally, the EThread class (derived from Thread)
+  maintains its own independent key. All (and only) the threads created
+  in the Event Subsystem are registered with this key. Thus, whenever you
+  call this_ethread() you get a pointer to EThread. If you happen to call
+  this_ethread() from inside a thread which is not an EThread, you will
+  get a nullptr value (since that thread will not be  registered with the
+  EThread key). This will hopefully make the use of this_ethread() safer.
+  Note that an event created with EThread can also call this_thread(),
+  in which case, it will get a pointer to Thread (rather than to EThread).
+
+ */
+
+#pragma once
+
+#include <functional>
+
+#include "ProxyAllocator.h"
+#include "tscore/Ptr.h"
+#include "tscore/ink_platform.h"
+#include "tscore/ink_thread.h"
+
+class ProxyMutex;
+
+constexpr int MAX_THREAD_NAME_LENGTH = 16;
+
+/// The signature of a function to be called by a thread.
+using ThreadFunction = std::function<void()>;
+
+/**
+  Base class for the threads in the Event System. Thread is the base
+  class for all the thread classes in the Event System. Objects of the
+  Thread class represent spawned or running threads and provide minimal
+  information for its derived classes. Thread objects have a reference
+  to a ProxyMutex, that is used for atomic operations internally, and
+  an ink_thread member that is used to identify the thread in the system.
+
+  You should not create an object of the Thread class, they are typically
+  instantiated after some thread startup mechanism exposed by a processor,
+  but even then you would probably deal with processor functions and
+  not the Thread object itself.
+
+*/
+class Thread
+{
+public:
+  /**
+    System-wide thread identifier. The thread identifier is represented
+    by the platform independent type ink_thread and it is the system-wide
+    value assigned to each thread. It is exposed as a convenience for
+    processors and you should not modify it directly.
+
+  */
+  // NOLINTNEXTLINE(modernize-use-nullptr)
+  ink_thread tid = 0;
+
+  /**
+    Thread lock to ensure atomic operations. The thread lock available
+    to derived classes to ensure atomic operations and protect critical
+    regions. Do not modify this member directly.
+
+  */
+  Ptr<ProxyMutex> mutex;
+
+  virtual void set_specific() = 0;
+
+  static thread_local Thread *this_thread_ptr;
+
+  // For THREAD_ALLOC
+  ProxyAllocator eventAllocator;
+  ProxyAllocator netVCAllocator;
+  ProxyAllocator sslNetVCAllocator;
+  ProxyAllocator quicNetVCAllocator;
+  ProxyAllocator http1ClientSessionAllocator;
+  ProxyAllocator http2ClientSessionAllocator;
+  ProxyAllocator http2ServerSessionAllocator;
+  ProxyAllocator http2StreamAllocator;
+  ProxyAllocator httpSMAllocator;
+  ProxyAllocator quicClientSessionAllocator;
+  ProxyAllocator httpServerSessionAllocator;
+  ProxyAllocator hdrHeapAllocator;
+  ProxyAllocator strHeapAllocator;
+  ProxyAllocator cacheVConnectionAllocator;
+  ProxyAllocator cacheEvacuateDocVConnectionAllocator;
+  ProxyAllocator openDirEntryAllocator;
+  ProxyAllocator ramCacheCLFUSEntryAllocator;
+  ProxyAllocator ramCacheLRUEntryAllocator;
+  ProxyAllocator evacuationBlockAllocator;
+  ProxyAllocator ioDataAllocator;
+  ProxyAllocator ioAllocator;
+  ProxyAllocator ioBlockAllocator;
+  ProxyAllocator preWarmSMAllocator;
+  // From InkAPI (plugins wrappers)
+  ProxyAllocator apiHookAllocator;
+  ProxyAllocator INKContAllocator;
+  ProxyAllocator INKVConnAllocator;
+  ProxyAllocator mHandleAllocator;
+
+  /** Start the underlying thread.
+
+      The thread name is set to @a name. The stack for the thread is either @a stack or, if that is
+      @c nullptr a stack of size @a stacksize is allocated and used. If @a f is present and valid it
+      is called in the thread context. Otherwise the method @c execute is invoked.
+  */
+  void start(const char *name, void *stack, size_t stacksize, ThreadFunction const &f = ThreadFunction());
+
+  virtual void execute() = 0;
+
+  /** Get the current ATS high resolution time.
+      This gets a cached copy of the time so it is very fast and reasonably accurate.
+      The cached time is updated every time the actual operating system time is fetched which is
+      at least every 10ms and generally more frequently.
+
+      @note The cached copy is thread local which means each thread need to update the cached copy by itself.
+  */
+
+  Thread(const Thread &)            = delete;
+  Thread &operator=(const Thread &) = delete;
+  virtual ~Thread();
+
+protected:
+  Thread();
+};
+
+extern Thread *this_thread();
diff --git a/include/iocore/eventsystem/VConnection.h b/include/iocore/eventsystem/VConnection.h
new file mode 100644
index 0000000000..d81a630d8d
--- /dev/null
+++ b/include/iocore/eventsystem/VConnection.h
@@ -0,0 +1,413 @@
+/** @file
+
+  Public VConnection declaration and associated declarations
+
+  @section license License
+
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+ */
+
+#pragma once
+
+#include "tscore/ink_platform.h"
+#include "tscore/PluginUserArgs.h"
+#include "EventSystem.h"
+
+#if !defined(I_VIO_h)
+#error "include VIO.h"
+#endif
+
+//
+// Data Types
+//
+#define VCONNECTION_CACHE_DATA_BASE 0
+#define VCONNECTION_NET_DATA_BASE   100
+#define VCONNECTION_API_DATA_BASE   200
+
+//
+// Event signals
+//
+
+#define VC_EVENT_NONE EVENT_NONE
+
+/** When a Continuation is first scheduled on a processor. */
+#define VC_EVENT_IMMEDIATE EVENT_IMMEDIATE
+
+#define VC_EVENT_READ_READY VC_EVENT_EVENTS_START
+
+/**
+  Any data in the associated buffer *will be written* when the
+  Continuation returns.
+
+*/
+#define VC_EVENT_WRITE_READY (VC_EVENT_EVENTS_START + 1)
+
+#define VC_EVENT_READ_COMPLETE  (VC_EVENT_EVENTS_START + 2)
+#define VC_EVENT_WRITE_COMPLETE (VC_EVENT_EVENTS_START + 3)
+
+/**
+  No more data (end of stream). It should be interpreted by a
+  protocol engine as either a COMPLETE or ERROR.
+
+*/
+#define VC_EVENT_EOS (VC_EVENT_EVENTS_START + 4)
+
+#define VC_EVENT_ERROR EVENT_ERROR
+
+/**
+  VC_EVENT_INACTIVITY_TIMEOUT indicates that the operation (read or write) has:
+    -# been enabled for more than the inactivity timeout period
+       (for a read, there has been space in the buffer)
+       (for a write, there has been data in the buffer)
+    -# no progress has been made
+       (for a read, no data has been read from the connection)
+       (for a write, no data has been written to the connection)
+
+*/
+#define VC_EVENT_INACTIVITY_TIMEOUT (VC_EVENT_EVENTS_START + 5)
+
+/**
+  Total time for some operation has been exceeded, regardless of any
+  intermediate progress.
+
+*/
+#define VC_EVENT_ACTIVE_TIMEOUT (VC_EVENT_EVENTS_START + 6)
+
+//
+// Event names
+//
+
+//
+// VC_EVENT_READ_READ occurs when data *has been written* into
+// the associated buffer.
+//
+// VC_EVENT_ERROR indicates that some error has occurred.  The
+// "data" will be either 0 if the errno is unavailable or errno.
+//
+// VC_EVENT_INTERVAL indicates that an interval timer has expired.
+//
+
+//
+// Event return codes
+//
+#define VC_EVENT_DONE CONTINUATION_DONE
+#define VC_EVENT_CONT CONTINUATION_CONT
+
+//////////////////////////////////////////////////////////////////////////////
+//
+//      Support Data Structures
+//
+//////////////////////////////////////////////////////////////////////////////
+
+/** Used in VConnection::shutdown(). */
+enum ShutdownHowTo_t {
+  IO_SHUTDOWN_READ = 0,
+  IO_SHUTDOWN_WRITE,
+  IO_SHUTDOWN_READWRITE,
+};
+
+/** Used in VConnection::get_data(). */
+enum TSApiDataType {
+  TS_API_DATA_READ_VIO = VCONNECTION_API_DATA_BASE,
+  TS_API_DATA_WRITE_VIO,
+  TS_API_DATA_OUTPUT_VC,
+  TS_API_DATA_CLOSED,
+  TS_API_DATA_LAST ///< Used by other classes to extend the enum values.
+};
+
+typedef struct tsapi_vio *TSVIO;
+
+/**
+  Base class for the connection classes that provide IO capabilities.
+
+  The VConnection class is an abstract representation of a uni or
+  bi-directional data conduit returned by a Processor. In a sense,
+  they serve a similar purpose to file descriptors. A VConnection
+  is a pure base class that defines methods to perform stream IO.
+  It is also a Continuation that is called back from processors.
+
+*/
+class VConnection : public Continuation
+{
+public:
+  ~VConnection() override;
+
+  /**
+    Read data from the VConnection.
+
+    Called by a state machine to read data from the VConnection.
+    Processors implementing read functionality take out lock, put
+    new bytes on the buffer and call the continuation back before
+    releasing the lock in order to enable the state machine to
+    handle transfer schemes where the end of a given transaction
+    is marked by a special character (ie: NNTP).
+
+    <b>Possible Event Codes</b>
+
+    On the callback to the continuation, the VConnection may use
+    on of the following values for the event code:
+
+    <table border="1">
+      <tr>
+        <td align="center"><b>Event code</b></td>
+        <td align="center"><b>Meaning</b></td>
+      </tr>
+      <tr>
+        <td>VC_EVENT_READ_READY</td>
+        <td>Data has been added to the buffer or the buffer is full</td>
+      </tr>
+      <tr>
+        <td>VC_EVENT_READ_COMPLETE</td>
+        <td>The amount of data indicated by 'nbytes' has been read into the
+            buffer</td>
+      </tr>
+      <tr>
+        <td>VC_EVENT_EOS</td>
+        <td>The stream being read from has been shutdown</td>
+      </tr>
+      <tr>
+        <td>VC_EVENT_ERROR</td>
+        <td>An error occurred during the read</td>
+      </tr>
+    </table>
+
+    @param c Continuation to be called back with events.
+    @param nbytes Number of bytes to read. If unknown, nbytes must
+      be set to INT64_MAX.
+    @param buf buffer to read into.
+    @return VIO representing the scheduled IO operation.
+
+  */
+  virtual VIO *do_io_read(Continuation *c = nullptr, int64_t nbytes = INT64_MAX, MIOBuffer *buf = nullptr) = 0;
+
+  /**
+    Write data to the VConnection.
+
+    This method is called by a state machine to write data to the
+    VConnection.
+
+    <b>Possible Event Codes</b>
+
+    On the callback to the continuation, the VConnection may use
+    on of the following event codes:
+
+    <table border="1">
+      <tr>
+        <td align="center"><b>Event code</b></td>
+        <td align="center"><b>Meaning</b></td>
+      </tr>
+      <tr>
+        <td>VC_EVENT_WRITE_READY</td>
+        <td>Data was written from the reader or there are no bytes available
+        for the reader to write.</td>
+      </tr>
+      <tr>
+        <td>VC_EVENT_WRITE_COMPLETE</td>
+        <td>The amount of data indicated by 'nbytes' has been written to the
+            VConnection</td>
+      </tr>
+      <tr>
+        <td>VC_EVENT_INACTIVITY_TIMEOUT</td>
+        <td>No activity was performed for a certain period.</td>
+      </tr>
+      <tr>
+        <td>VC_EVENT_ACTIVE_TIMEOUT</td>
+        <td>Write operation continued beyond a time limit.</td>
+      </tr>
+      <tr>
+        <td>VC_EVENT_ERROR</td>
+        <td>An error occurred during the write</td>
+      </tr>
+    </table>
+
+    @param c Continuation to be called back with events.
+    @param nbytes Number of bytes to write. If unknown, nbytes must
+      be set to INT64_MAX.
+    @param buf Reader whose data is to be read from.
+    @param owner
+    @return VIO representing the scheduled IO operation.
+
+  */
+  virtual VIO *do_io_write(Continuation *c = nullptr, int64_t nbytes = INT64_MAX, IOBufferReader *buf = nullptr,
+                           bool owner = false) = 0;
+
+  /**
+    Indicate that the VConnection is no longer needed.
+
+    Once the state machine has finished using this VConnection, it
+    must call this function to indicate that the VConnection can
+    be deallocated.  After a close has been called, the VConnection
+    and underlying processor must not send any more events related
+    to this VConnection to the state machine. Likewise, the state
+    machine must not access the VConnection or any VIOs obtained
+    from it after calling this method.
+
+    @param lerrno indicates where a close is a normal close or an
+      abort. The difference between a normal close and an abort
+      depends on the underlying type of the VConnection.
+
+  */
+  virtual void do_io_close(int lerrno = -1) = 0;
+
+  /**
+    Terminate one or both directions of the VConnection.
+
+    Indicates that one or both sides of the VConnection should be
+    terminated. After this call is issued, no further I/O can be
+    done on the specified direction of the connection. The processor
+    must not send any further events (including timeout events) to
+    the state machine, and the state machine must not use any VIOs
+    from a shutdown direction of the connection. Even if both sides
+    of a connection are shutdown, the state machine must still call
+    do_io_close() when it wishes the VConnection to be deallocated.
+
+    <b>Possible howto values</b>
+
+    <table border="1">
+      <tr>
+        <td align="center"><b>Value</b></td>
+        <td align="center"><b>Meaning</b></td>
+      </tr>
+      <tr>
+        <td>IO_SHUTDOWN_READ</td>
+        <td>Indicates that this VConnection should not generate any more
+        read events</td>
+      </tr>
+      <tr>
+        <td>IO_SHUTDOWN_WRITE</td>
+        <td>Indicates that this VConnection should not generate any more
+        write events</td>
+      </tr>
+      <tr>
+        <td>IO_SHUTDOWN_READWRITE</td>
+        <td>Indicates that this VConnection should not generate any more
+        read nor write events</td>
+      </tr>
+    </table>
+
+    @param howto Specifies which direction of the VConnection to
+      shutdown.
+
+  */
+  virtual void do_io_shutdown(ShutdownHowTo_t howto) = 0;
+
+  explicit VConnection(ProxyMutex *aMutex);
+  explicit VConnection(Ptr<ProxyMutex> &aMutex);
+
+  // Private
+  // Set continuation on a given vio. The public interface
+  // is through VIO::set_continuation()
+  virtual void set_continuation(VIO *vio, Continuation *cont);
+
+  // Reenable a given vio.  The public interface is through VIO::reenable
+  virtual void reenable(VIO *vio);
+  virtual void reenable_re(VIO *vio);
+
+  /**
+    Convenience function to retrieve information from VConnection.
+
+    This function is provided as a convenience for state machines
+    to transmit information from/to a VConnection without breaking
+    the VConnection abstraction. Its behavior varies depending on
+    the type of VConnection being used.
+
+    @param id Identifier associated to interpret the data field
+    @param data Value or pointer with state machine or VConnection data.
+    @return True if the operation is successful.
+
+  */
+  virtual bool
+  get_data(int id, void *data)
+  {
+    (void)id;
+    (void)data;
+    return false;
+  }
+
+  /**
+    Convenience function to set information into the VConnection.
+
+    This function is provided as a convenience for state machines
+    to transmit information from/to a VConnection without breaking
+    the VConnection abstraction. Its behavior varies depending on
+    the type of VConnection being used.
+
+    @param id Identifier associated to interpret the data field.
+    @param data Value or pointer with state machine or VConnection data.
+    @return True if the operation is successful.
+
+  */
+  virtual bool
+  set_data(int id, void *data)
+  {
+    (void)id;
+    (void)data;
+    return false;
+  }
+
+  // This function should be called when the VConnection is a tunnel endpoint.  By default, a VConnection does not care if it
+  // is a tunnel endpoint.
+  virtual void
+  mark_as_tunnel_endpoint()
+  {
+  }
+
+  /**
+    The error code from the last error.
+
+    Indicates the last error on the VConnection. They are either
+    system error codes or from the InkErrno.h file.
+
+  */
+  int lerrno;
+};
+
+struct DummyVConnection : public VConnection, public PluginUserArgs<TS_USER_ARGS_VCONN> {
+  VIO *
+  do_io_write(Continuation * /* c ATS_UNUSED */, int64_t /* nbytes ATS_UNUSED */, IOBufferReader * /* buf ATS_UNUSED */,
+              bool /* owner ATS_UNUSED */) override
+  {
+    ink_assert(!"VConnection::do_io_write -- "
+                "cannot use default implementation");
+    return nullptr;
+  }
+
+  VIO *
+  do_io_read(Continuation * /* c ATS_UNUSED */, int64_t /* nbytes ATS_UNUSED */, MIOBuffer * /* buf ATS_UNUSED */) override
+  {
+    ink_assert(!"VConnection::do_io_read -- "
+                "cannot use default implementation");
+    return nullptr;
+  }
+
+  void
+  do_io_close(int /* alerrno ATS_UNUSED */) override
+  {
+    ink_assert(!"VConnection::do_io_close -- "
+                "cannot use default implementation");
+  }
+
+  void
+  do_io_shutdown(ShutdownHowTo_t /* howto ATS_UNUSED */) override
+  {
+    ink_assert(!"VConnection::do_io_shutdown -- "
+                "cannot use default implementation");
+  }
+
+  explicit DummyVConnection(ProxyMutex *m) : VConnection(m) {}
+};
diff --git a/include/iocore/eventsystem/VIO.h b/include/iocore/eventsystem/VIO.h
new file mode 100644
index 0000000000..8099b212c1
--- /dev/null
+++ b/include/iocore/eventsystem/VIO.h
@@ -0,0 +1,223 @@
+/** @file
+
+  A brief file description
+
+  @section license License
+
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+ */
+
+#pragma once
+#define I_VIO_h
+
+#if !defined(I_IOBuffer_h)
+#error "include IOBuffer.h"
+#endif
+
+class Continuation;
+class VConnection;
+class ProxyMutex;
+
+/**
+  Descriptor for an IO operation.
+
+  A VIO is a descriptor for an in progress IO operation. It is
+  returned from do_io_read() and do_io_write() methods on VConnections.
+  Through the VIO, the state machine can monitor the progress of
+  an operation and reenable the operation when data becomes available.
+
+  The VIO operation represents several types of operations, and
+  they can be identified through the 'op' member. It can take any
+  of the following values:
+
+  <table>
+    <tr>
+      <td align="center"><b>Constant</b></td>
+      <td align="center"><b>Meaning</b></td>
+    </tr>
+    <tr><td>READ</td><td>The VIO represents a read operation</td></tr>
+    <tr><td>WRITE</td><td>The VIO represents a write operation</td></tr>
+    <tr><td>CLOSE</td><td>The VIO represents the request to close the
+                          VConnection</td></tr>
+    <tr><td>ABORT</td><td></td></tr>
+    <tr><td>SHUTDOWN_READ</td><td></td></tr>
+    <tr><td>SHUTDOWN_WRITE</td><td></td></tr>
+    <tr><td>SHUTDOWN_READWRITE</td><td></td></tr>
+    <tr><td>SEEK</td><td></td></tr>
+    <tr><td>PREAD</td><td></td></tr>
+    <tr><td>PWRITE</td><td></td></tr>
+    <tr><td>STAT</td><td></td></tr>
+  </table>
+
+*/
+class VIO
+{
+public:
+  explicit VIO(int aop);
+  VIO();
+  ~VIO() {}
+
+  /** Interface for the VConnection that owns this handle. */
+  Continuation *get_continuation() const;
+  void set_continuation(Continuation *cont);
+
+  /**
+    Set nbytes to be what is current available.
+
+    Interface to set nbytes to be ndone + buffer.reader()->read_avail()
+    if a reader is set.
+  */
+  void done();
+
+  /**
+    Determine the number of bytes remaining.
+
+    Convenience function to determine how many bytes the operation
+    has remaining.
+
+    @return The number of bytes to be processed by the operation.
+
+  */
+  int64_t ntodo() const;
+
+  /////////////////////
+  // buffer settings //
+  /////////////////////
+  void set_writer(MIOBuffer *writer);
+  void set_reader(IOBufferReader *reader);
+  MIOBuffer *get_writer() const;
+  IOBufferReader *get_reader() const;
+
+  /**
+    Reenable the IO operation.
+
+    Interface that the state machine uses to reenable an I/O
+    operation.  Reenable tells the VConnection that more data is
+    available for the operation and that it should try to continue
+    the operation in progress.  I/O operations become disabled when
+    they can make no forward progress.  For a read this means that
+    it's buffer is full. For a write, that it's buffer is empty.
+    If reenable is called and progress is still not possible, it
+    is ignored and no events are generated. However, unnecessary
+    reenables (ones where no progress can be made) should be avoided
+    as they hurt system throughput and waste CPU.
+
+  */
+  void reenable();
+
+  /**
+    Reenable the IO operation.
+
+    Interface that the state machine uses to reenable an I/O
+    operation.  Reenable tells the VConnection that more data is
+    available for the operation and that it should try to continue
+    the operation in progress.  I/O operations become disabled when
+    they can make no forward progress.  For a read this means that
+    it's buffer is full. For a write, that it's buffer is empty.
+    If reenable is called and progress is still not possible, it
+    is ignored and no events are generated. However, unnecessary
+    reenables (ones where no progress can be made) should be avoided
+    as they hurt system throughput and waste CPU.
+
+  */
+  void reenable_re();
+
+  void disable();
+  bool is_disabled() const;
+
+  enum {
+    NONE = 0,
+    READ,
+    WRITE,
+    CLOSE,
+    ABORT,
+    SHUTDOWN_READ,
+    SHUTDOWN_WRITE,
+    SHUTDOWN_READWRITE,
+    SEEK,
+    PREAD,
+    PWRITE,
+    STAT,
+  };
+
+  /**
+    Continuation to callback.
+
+    Used by the VConnection to store who is the continuation to
+    call with events for this operation.
+
+  */
+  Continuation *cont = nullptr;
+
+  /**
+    Number of bytes to be done for this operation.
+
+    The total number of bytes this operation must complete.
+
+  */
+  int64_t nbytes = 0;
+
+  /**
+    Number of bytes already completed.
+
+    The number of bytes that already have been completed for the
+    operation. Processor can update this value only if they hold
+    the lock.
+
+  */
+  int64_t ndone = 0;
+
+  /**
+    Type of operation.
+
+    The type of operation that this VIO represents.
+
+  */
+  int op = VIO::NONE;
+
+  // This is a little odd location, but this saves on padding, and an entire cache line
+private:
+  bool _disabled = false;
+
+public:
+  /**
+    Provides access to the reader or writer for this operation.
+
+    Contains a pointer to the IOBufferReader if the operation is a
+    write and a pointer to a MIOBuffer if the operation is a read.
+
+  */
+  MIOBufferAccessor buffer;
+
+  /**
+    Internal backpointer to the VConnection for use in the reenable
+    functions.
+
+  */
+  VConnection *vc_server = nullptr;
+
+  /**
+    Reference to the state machine's mutex.
+
+    Maintains a reference to the state machine's mutex to allow
+    processors to safely lock the operation even if the state machine
+    has closed the VConnection and deallocated itself.
+
+  */
+  Ptr<ProxyMutex> mutex;
+};
diff --git a/include/iocore/hostdb/HostDB.h b/include/iocore/hostdb/HostDB.h
new file mode 100644
index 0000000000..61c488c50e
--- /dev/null
+++ b/include/iocore/hostdb/HostDB.h
@@ -0,0 +1,41 @@
+/** @file
+
+  A brief file description
+
+  @section license License
+
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ */
+
+/****************************************************************************
+
+  I_HostDB.h
+
+
+ ****************************************************************************/
+
+#pragma once
+
+#include "EventSystem.h"
+#include "Net.h"
+
+#include "HostDBProcessor.h"
+
+// TS-1925: switch from MMH to MD5 hash; bumped to version 2
+// switch from MD5 to SHA256 hash; bumped to version 3
+// 2.1: Switched to mark RR elements.
+static constexpr ts::ModuleVersion HOSTDB_MODULE_PUBLIC_VERSION(3, 1);
diff --git a/include/iocore/hostdb/HostDBProcessor.h b/include/iocore/hostdb/HostDBProcessor.h
new file mode 100644
index 0000000000..760a8924dc
--- /dev/null
+++ b/include/iocore/hostdb/HostDBProcessor.h
@@ -0,0 +1,887 @@
+/** @file
+
+  A brief file description
+
+  @section license License
+
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ */
+
+#pragma once
+
+#include <chrono>
+#include <atomic>
+
+#include "tscore/HashFNV.h"
+#include "tscore/ink_time.h"
+#include "tscore/CryptoHash.h"
+#include "tscore/ink_align.h"
+#include "tscore/ink_inet.h"
+#include "tscore/ink_resolver.h"
+#include "tscore/HTTPVersion.h"
+
+#include "swoc/MemSpan.h"
+
+#include "EventSystem.h"
+#include "SRV.h"
+
+// Event returned on a lookup
+#define EVENT_HOST_DB_LOOKUP       (HOSTDB_EVENT_EVENTS_START + 0)
+#define EVENT_HOST_DB_IP_REMOVED   (HOSTDB_EVENT_EVENTS_START + 1)
+#define EVENT_HOST_DB_GET_RESPONSE (HOSTDB_EVENT_EVENTS_START + 2)
+
+#define EVENT_SRV_LOOKUP       (SRV_EVENT_EVENTS_START + 0)
+#define EVENT_SRV_IP_REMOVED   (SRV_EVENT_EVENTS_START + 1)
+#define EVENT_SRV_GET_RESPONSE (SRV_EVENT_EVENTS_START + 2)
+
+//
+// Data
+//
+struct HostDBContinuation;
+struct ResolveInfo;
+
+//
+// The host database stores host information, most notably the
+// IP address.
+//
+// Since host information is relatively small, we can afford to have
+// a reasonable size memory cache, and use a (relatively) sparse
+// disk representation to decrease # of seeks.
+//
+extern int hostdb_enable;
+/** Epoch timestamp of the current hosts file check.
+ *
+ * This also functions as a cached version of ts_clock::now(). Since it is
+ * updated in backgroundEvent which runs every second, it should be
+ * approximately accurate to a second.
+ */
+extern std::atomic<ts_time> hostdb_current_timestamp;
+
+/** How long before any DNS response is consided stale, regardless of DNS TTL.
+ * This corresponds to proxy.config.hostdb.verify_after.
+ */
+extern unsigned int hostdb_ip_stale_interval;
+extern unsigned int hostdb_ip_timeout_interval;
+extern unsigned int hostdb_ip_fail_timeout_interval;
+extern unsigned int hostdb_serve_stale_but_revalidate;
+extern unsigned int hostdb_round_robin_max_count;
+
+extern int hostdb_max_iobuf_index;
+
+static inline unsigned int
+makeHostHash(const char *string)
+{
+  ink_assert(string && *string);
+
+  if (string && *string) {
+    ATSHash32FNV1a fnv;
+    fnv.update(string, strlen(string), ATSHash::nocase());
+    fnv.final();
+    return fnv.get();
+  }
+
+  return 0;
+}
+
+//
+// Types
+//
+
+class HostDBRecord;
+
+/// Information for an SRV record.
+struct SRVInfo {
+  unsigned int srv_offset   : 16; ///< Memory offset from @c HostDBInfo to name.
+  unsigned int srv_weight   : 16;
+  unsigned int srv_priority : 16;
+  unsigned int srv_port     : 16;
+  unsigned int key;
+};
+
+/// Type of data stored.
+enum class HostDBType : uint8_t {
+  UNSPEC, ///< No valid data.
+  ADDR,   ///< IP address.
+  SRV,    ///< SRV record.
+  HOST    ///< Hostname (reverse DNS)
+};
+char const *name_of(HostDBType t);
+
+/** Information about a single target.
+ */
+struct HostDBInfo {
+  using self_type = HostDBInfo; ///< Self reference type.
+
+  /// Default constructor.
+  HostDBInfo() = default;
+
+  HostDBInfo &operator=(HostDBInfo const &that);
+
+  /// Absolute time of when this target failed.
+  /// A value of zero (@c TS_TIME_ZERO ) indicates no failure.
+  ts_time last_fail_time() const;
+
+  /// Target is alive - no known failure.
+  bool is_alive();
+
+  /// Target has failed and is still in the blocked time window.
+  bool is_down(ts_time now, ts_seconds fail_window);
+
+  /** Select this target.
+   *
+   * @param now Current time.
+   * @param fail_window Failure window.
+   * @return Status of the selection.
+   *
+   * If a zombie is selected the failure time is updated to make it appear down to other threads in a thread safe
+   * manner. The caller should check @c last_fail_time to see if a zombie was selected.
+   */
+  bool select(ts_time now, ts_seconds fail_window);
+
+  /// Check if this info is valid.
+  bool is_valid() const;
+
+  /// Mark this info as invalid.
+  void invalidate();
+
+  /** Mark the entry as down.
+   *
+   * @param now Time of the failure.
+   * @return @c true if @a this was marked down, @c false if not.
+   *
+   * This can return @c false if the entry is already marked down, in which case the failure time is not updated.
+   */
+  bool mark_down(ts_time now);
+
+  /** Mark the target as up / alive.
+   *
+   * @return Previous alive state of the target.
+   */
+  bool mark_up();
+
+  char const *srvname() const;
+
+  /** Migrate data after a DNS update.
+   *
+   * @param that Source item.
+   *
+   * This moves only specific state information, it is not a generic copy.
+   */
+  void migrate_from(self_type const &that);
+
+  /// A target is either an IP address or an SRV record.
+  /// The type should be indicated by @c flags.f.is_srv;
+  union {
+    IpAddr ip;   ///< IP address / port data.
+    SRVInfo srv; ///< SRV record.
+  } data{IpAddr{}};
+
+  /// Data that migrates after updated DNS records are processed.
+  /// @see migrate_from
+  /// @{
+  /// Last time a failure was recorded.
+  std::atomic<ts_time> last_failure{TS_TIME_ZERO};
+  /// Count of connection failures
+  std::atomic<uint8_t> fail_count{0};
+  /// Expected HTTP version of the target based on earlier transactions.
+  HTTPVersion http_version = HTTP_INVALID;
+  /// @}
+
+  self_type &assign(IpAddr const &addr);
+
+protected:
+  self_type &assign(sa_family_t af, void const *addr);
+  self_type &assign(SRV const *srv, char const *name);
+
+  HostDBType type = HostDBType::UNSPEC; ///< Invalid data.
+
+  friend HostDBContinuation;
+};
+
+inline HostDBInfo &
+HostDBInfo::operator=(HostDBInfo const &that)
+{
+  if (this != &that) {
+    memcpy(static_cast<void *>(this), static_cast<const void *>(&that), sizeof(*this));
+  }
+  return *this;
+}
+
+inline ts_time
+HostDBInfo::last_fail_time() const
+{
+  return last_failure;
+}
+
+inline bool
+HostDBInfo::is_alive()
+{
+  return this->last_fail_time() == TS_TIME_ZERO;
+}
+
+inline bool
+HostDBInfo::is_down(ts_time now, ts_seconds fail_window)
+{
+  auto last_fail = this->last_fail_time();
+  return (last_fail != TS_TIME_ZERO) && (last_fail + fail_window < now);
+}
+
+inline bool
+HostDBInfo::mark_up()
+{
+  auto t = last_failure.exchange(TS_TIME_ZERO);
+  return t != TS_TIME_ZERO;
+}
+
+inline bool
+HostDBInfo::mark_down(ts_time now)
+{
+  auto t0{TS_TIME_ZERO};
+  return last_failure.compare_exchange_strong(t0, now);
+}
+
+inline bool
+HostDBInfo::select(ts_time now, ts_seconds fail_window)
+{
+  auto t0 = this->last_fail_time();
+  if (t0 == TS_TIME_ZERO) {
+    return true; // it's alive and so is valid for selection.
+  }
+  // Success means this is a zombie and this thread updated the failure time.
+  return (t0 + fail_window < now) && last_failure.compare_exchange_strong(t0, now);
+}
+
+inline void
+HostDBInfo::migrate_from(HostDBInfo::self_type const &that)
+{
+  this->last_failure = that.last_failure.load();
+  this->http_version = that.http_version;
+}
+
+inline bool
+HostDBInfo::is_valid() const
+{
+  return type != HostDBType::UNSPEC;
+}
+
+inline void
+HostDBInfo::invalidate()
+{
+  type = HostDBType::UNSPEC;
+}
+
+// ----
+/** Root item for HostDB.
+ * This is the container for HostDB data. It is always an array of @c HostDBInfo instances plus metadata.
+ * All strings are C-strings and therefore don't need a distinct size.
+ *
+ */
+class HostDBRecord : public RefCountObj
+{
+  friend struct HostDBContinuation;
+  friend struct ShowHostDB;
+  using self_type = HostDBRecord;
+
+  /// Size of the IO buffer block owned by @a this.
+  /// If negative @a this is in not allocated memory.
+  int _iobuffer_index{-1};
+  /// Actual size of the data.
+  unsigned _record_size = sizeof(self_type);
+
+public:
+  HostDBRecord()                      = default;
+  HostDBRecord(self_type const &that) = delete;
+
+  using Handle = Ptr<HostDBRecord>; ///< Shared pointer type to hold an instance.
+
+  /** Allocate an instance from the IOBuffers.
+   *
+   * @param query_name Name of the query for the record.
+   * @param rr_count Number of info instances.
+   * @param srv_name_size Storage for SRV names, if any.
+   * @return An instance sufficient to hold the specified data.
+   *
+   * The query name will stored and initialized, and the info instances initialized.
+   */
+  static self_type *alloc(swoc::TextView query_name, unsigned rr_count, size_t srv_name_size = 0);
+
+  /// Type of data stored in this record.
+  HostDBType record_type = HostDBType::UNSPEC;
+
+  /// IP family of this record.
+  sa_family_t af_family = AF_UNSPEC;
+
+  /// Offset from @a this to the VLA.
+  unsigned short rr_offset = 0;
+
+  /// Number of @c HostDBInfo instances.
+  unsigned short rr_count = 0;
+
+  /// Timing data for switch records in the RR.
+  std::atomic<ts_time> rr_ctime{TS_TIME_ZERO};
+
+  /// Hash key.
+  uint64_t key{0};
+
+  /// When the DNS response was received.
+  ts_time ip_timestamp;
+
+  /// Valid duration of the DNS response data.
+  /// In the code this functions as the TTL in HostDB calculations, but may not
+  /// be the response's TTL based upon configuration such as
+  /// proxy.config.hostdb.ttl_mode.
+  ts_seconds ip_timeout_interval;
+
+  /** Atomically advance the round robin index.
+   *
+   * If multiple threads call this simultaneously each thread will get a distinct return value.
+   *
+   * @return The new round robin index.
+   */
+  unsigned next_rr();
+
+  /** Pick the next round robin and update the record atomically.
+   *
+   * @note This may select a zombie server and reserve it for the caller, therefore the caller must
+   * attempt to connect to the selected target if possible.
+   *
+   * @param now Current time to use for aliveness calculations.
+   * @param fail_window Blackout time for down servers.
+   * @return Status of the updated target.
+   *
+   * If the return value is @c HostDBInfo::Status::DOWN this means all targets are down and there is
+   * no valid upstream.
+   *
+   * @note Concurrency - this is not done under lock and depends on the caller for correct use.
+   * For strict round robin, it is a feature that every call will get a distinct index. For
+   * timed round robin, the caller must arrange to have only one thread call this per time interval.
+   */
+  HostDBInfo *select_next_rr(ts_time now, ts_seconds fail_window);
+
+  /// Check if this record is of SRV targets.
+  bool is_srv() const;
+
+  /** Query name for the record.
+   * @return A C-string.
+   * If this is a @c HOST record, this is the resolved named and the query was based on the IP address.
+   * Otherwise this is the name used in the DNS query.
+   */
+  char const *name() const;
+
+  /** Query name for the record.
+   * @return A view.
+   * If this is a @c HOST record, this is the resolved named and the query was based on the IP address.
+   * Otherwise this is the name used in the DNS query.
+   * @note Although not included in the view, the name is always nul terminated and the string can
+   * be used as a C-string.
+   */
+  swoc::TextView name_view() const;
+
+  /// Get the array of info instances.
+  swoc::MemSpan<HostDBInfo> rr_info();
+
+  /** Find a host record by IP address.
+   *
+   * @param addr Address key.
+   * @return A pointer to the info instance if a match is found, @c nullptr if not.
+   */
+  HostDBInfo *find(sockaddr const *addr);
+
+  /** Select an upstream target.
+   *
+   * @param now Current time.
+   * @param fail_window Down server blackout time.
+   * @param hash_addr Inbound remote IP address.
+   * @return A selected target, or @c nullptr if there are no valid targets.
+   *
+   * This accounts for the round robin setting. The default is to use "client affinity" in
+   * which case @a hash_addr is as a hash seed to select the target.
+   *
+   * This may select a zombie target, which can be detected by checking the target's last
+   * failure time. If it is not @c TS_TIME_ZERO the target is a zombie. Other transactions will
+   * be blocked from selecting that target until @a fail_window time has passed.
+   *
+   * In cases other than strict round robin, a base target is selected. If valid, that is returned,
+   * but if not then the targets in this record are searched until a valid one is found. The result
+   * is this can be called to select a target for failover when a previous target fails.
+   */
+  HostDBInfo *select_best_http(ts_time now, ts_seconds fail_window, sockaddr const *hash_addr);
+  HostDBInfo *select_best_srv(char *target, InkRand *rand, ts_time now, ts_seconds fail_window);
+
+  bool is_failed() const;
+
+  void set_failed();
+
+  /// @return The time point when the item expires.
+  ts_time expiry_time() const;
+
+  /// @return The age of the DNS response.
+  ts_seconds ip_age() const;
+
+  /// @return How long before the DNS response becomes stale (i.e., exceeds @a
+  /// ip_timeout_interval from the time of the response).
+  ts_seconds ip_time_remaining() const;
+
+  /// @return Whether the age of the DNS response exceeds @a the user's
+  /// configured proxy.config.hostdb.verify_after value.
+  bool is_ip_configured_stale() const;
+
+  /** Whether we have exceeded the DNS response's TTL (i.e., whether the DNS
+   * response is stale). */
+  bool is_ip_timeout() const;
+
+  bool is_ip_fail_timeout() const;
+
+  void refresh_ip();
+
+  /** Whether the DNS response can still be used per
+   * proxy.config.hostdb.serve_stale_for configuration.
+   *
+   * @return False if serve_stale_for is not configured or if the DNS
+   * response's age is less than TTL + the serve_stale_for value. Note that
+   * this function will return true for DNS responses whose age is less than
+   * TTL (i.e., for responses that are not yet stale).
+   */
+  bool serve_stale_but_revalidate() const;
+
+  /// Deallocate @a this.
+  void free() override;
+
+  /** The current round robin index.
+   *
+   * @return The current index.
+   *
+   * @note The internal index may be out of range due to concurrency constraints - this insures the
+   * returned value is in range.
+   */
+  unsigned short rr_idx() const;
+
+  /** Offset from the current round robin index.
+   *
+   * @param delta Distance from the current index.
+   * @return The effective index.
+   */
+  unsigned short rr_idx(unsigned short delta) const;
+
+  /// The index of @a target in this record.
+  int index_of(HostDBInfo const *target) const;
+
+  /** Allocation and initialize an instance from a serialized buffer.
+   *
+   * @param buff Serialization data.
+   * @param size Size of @a buff.
+   * @return An instance initialized from @a buff.
+   */
+  static self_type *unmarshall(char *buff, unsigned size);
+
+  /// Database version.
+  static constexpr ts::VersionNumber Version{3, 0};
+
+protected:
+  /// Current active info.
+  /// @note This value may be out of range due to the difficulty of synchronization, therefore
+  /// must always be taken modulus @c rr_count when used. Use the @c rr_idx() method unless
+  /// raw access is required.
+  std::atomic<unsigned short> _rr_idx = 0;
+
+  /** Access an internal object at @a offset.
+   *
+   * @tparam T Type of object.
+   * @param offset Offset of object.
+   * @return A pointer to the object of type @a T.
+   *
+   * @a offset is applied to @a this record and the result cast to a pointer to @a T.
+   *
+   * @note @a offset based at @a this.
+   */
+  template <typename T>
+  T *
+  apply_offset(unsigned offset)
+  {
+    return reinterpret_cast<T *>(reinterpret_cast<char *>(this) + offset);
+  }
+
+  template <typename T>
+  T const *
+  apply_offset(unsigned offset) const
+  {
+    return reinterpret_cast<T const *>(reinterpret_cast<char const *>(this) + offset);
+  }
+
+  union {
+    uint16_t all;
+    struct {
+      unsigned failed_p : 1; ///< DNS error.
+    } f;
+  } flags{0};
+};
+
+struct HostDBCache;
+struct HostDBHash;
+
+// Prototype for inline completion function or
+//  getbyname_imm()
+using cb_process_result_pfn = void (Continuation::*)(HostDBRecord *r);
+
+Action *iterate(Continuation *cont);
+
+/** Information for doing host resolution for a request.
+ *
+ * This is effectively a state object for a request attempting to connect upstream. Information about its attempt
+ * that are local to the request are kept here, while shared data is accessed via the @c HostDBInfo pointers.
+ *
+ * A primitive version of the IP address generator concept.
+ */
+struct ResolveInfo {
+  using self_type = ResolveInfo; ///< Self reference type.
+
+  /// Not quite sure what this is for.
+  enum UpstreamResolveStyle { UNDEFINED_LOOKUP, ORIGIN_SERVER, PARENT_PROXY, HOST_NONE };
+
+  /** Origin server address source selection.
+
+      If config says to use CTA (client target addr) state is TRY_CLIENT, otherwise it
+      remains the default. If the connect fails then we switch to a USE. We go to USE_HOSTDB if (1)
+      the HostDB lookup is successful and (2) some address other than the CTA is available to try.
+      Otherwise we keep retrying on the CTA (USE_CLIENT) up to the max retry value.  In essence we
+      try to treat the CTA as if it were another RR value in the HostDB record.
+   */
+  enum class OS_Addr {
+    TRY_DEFAULT, ///< Initial state, use what config says.
+    TRY_HOSTDB,  ///< Try HostDB data.
+    TRY_CLIENT,  ///< Try client target addr.
+    USE_HOSTDB,  ///< Force use of HostDB target address.
+    USE_CLIENT,  ///< Force client target addr.
+    USE_API      ///< Use the API provided address.
+  };
+
+  ResolveInfo()  = default;
+  ~ResolveInfo() = default;
+
+  /// Keep a reference to the base HostDB object, so it doesn't get GC'd.
+  Ptr<HostDBRecord> record;
+  HostDBInfo *active = nullptr; ///< Active host record.
+
+  /// Working address. The meaning / source of the value depends on other elements.
+  /// This is the "resolved" address if @a resolved_p is @c true.
+  IpEndpoint addr;
+
+  int attempts = 0; ///< Number of connection attempts.
+
+  char const *lookup_name             = nullptr;
+  char srv_hostname[MAXDNAME]         = {0};
+  const sockaddr *inbound_remote_addr = nullptr; ///< Remote address of inbound client - used for hashing.
+  in_port_t srv_port                  = 0;       ///< Port from SRV lookup or API call.
+
+  OS_Addr os_addr_style           = OS_Addr::TRY_DEFAULT;
+  HostResStyle host_res_style     = HOST_RES_IPV4;
+  UpstreamResolveStyle looking_up = UNDEFINED_LOOKUP;
+
+  HTTPVersion http_version = HTTP_INVALID;
+
+  bool resolved_p = false; ///< If there is a valid, resolved address in @a addr.
+
+  /// Flag for @a addr being set externally.
+  //  bool api_addr_set_p = false;
+
+  /*** Set to true by default.  If use_client_target_address is set
+   * to 1, this value will be set to false if the client address is
+   * not in the DNS pool */
+  bool cta_validated_p = true;
+
+  bool set_active(HostDBInfo *info);
+
+  bool set_active(sockaddr const *s);
+
+  bool set_active(std::nullptr_t);
+
+  /** Force a resolved address.
+   *
+   * @param sa Address to use for the upstream.
+   * @return @c true if successful, @c false if error.
+   *
+   * This fails if @a sa isn't a valid IP address.
+   */
+  bool set_upstream_address(const sockaddr *sa);
+
+  bool set_upstream_address(IpAddr const &ip_addr);
+
+  void set_upstream_port(in_port_t port);
+
+  /** Check and (if possible) immediately resolve the upstream address without consulting the HostDB.
+   * The cases where this is successful are
+   * - The address is already resolved (@a resolved_p is @c true).
+   * - The upstream was set explicitly.
+   * - The hostname is a valid IP address.
+   *
+   * @return @c true if the upstream address was resolved, @c false if not.
+   */
+  bool resolve_immediate();
+
+  /** Mark the active target as down.
+   *
+   * @param now Time of failure.
+   * @return @c true if the server was marked as down, @c false if not.
+   *
+   */
+  bool mark_active_server_down(ts_time now);
+
+  /** Mark the active target as alive.
+   *
+   * @return @c true if the target changed state.
+   */
+  bool mark_active_server_alive();
+
+  /// Select / resolve to the next RR entry for the record.
+  bool select_next_rr();
+
+  bool is_srv() const;
+};
+
+/** The Host Database access interface. */
+struct HostDBProcessor : public Processor {
+  // Public Interface
+
+  // Lookup Hostinfo by name
+  //    cont->handleEvent( EVENT_HOST_DB_LOOKUP, HostDBInfo * ); on success
+  //    cont->handleEVent( EVENT_HOST_DB_LOOKUP, 0); on failure
+  // Failure occurs when the host cannot be DNS-ed
+  // NOTE: Will call the continuation back before returning if data is in the
+  //       cache.  The HostDBInfo * becomes invalid when the callback returns.
+  //       The HostDBInfo may be changed during the callback.
+
+  enum {
+    HOSTDB_DO_NOT_FORCE_DNS   = 0,
+    HOSTDB_ROUND_ROBIN        = 0,
+    HOSTDB_FORCE_DNS_RELOAD   = 1,
+    HOSTDB_FORCE_DNS_ALWAYS   = 2,
+    HOSTDB_DO_NOT_ROUND_ROBIN = 4
+  };
+
+  /// Optional parameters for getby...
+  struct Options {
+    using self                  = Options;                 ///< Self reference type.
+    int port                    = 0;                       ///< Target service port (default 0 -> don't care)
+    int flags                   = HOSTDB_DO_NOT_FORCE_DNS; ///< Processing flags (default HOSTDB_DO_NOT_FORCE_DNS)
+    int timeout                 = 0;                       ///< Timeout value (default 0 -> default timeout)
+    HostResStyle host_res_style = HOST_RES_IPV4;           ///< How to query host (default HOST_RES_IPV4)
+
+    Options() {}
+    /// Set the flags.
+    self &
+    setFlags(int f)
+    {
+      flags = f;
+      return *this;
+    }
+  };
+
+  /// Default options.
+  static Options const DEFAULT_OPTIONS;
+
+  HostDBProcessor() {}
+  Action *getbyname_re(Continuation *cont, const char *hostname, int len, Options const &opt = DEFAULT_OPTIONS);
+
+  Action *getbynameport_re(Continuation *cont, const char *hostname, int len, Options const &opt = DEFAULT_OPTIONS);
+
+  Action *getSRVbyname_imm(Continuation *cont, cb_process_result_pfn process_srv_info, const char *hostname, int len,
+                           Options const &opt = DEFAULT_OPTIONS);
+
+  Action *getbyname_imm(Continuation *cont, cb_process_result_pfn process_hostdb_info, const char *hostname, int len,
+                        Options const &opt = DEFAULT_OPTIONS);
+
+  Action *iterate(Continuation *cont);
+
+  /** Lookup Hostinfo by addr */
+  Action *getbyaddr_re(Continuation *cont, sockaddr const *aip);
+
+  /** Configuration. */
+  static int hostdb_strict_round_robin;
+  static int hostdb_timed_round_robin;
+
+  // Processor Interface
+  /* hostdb does not use any dedicated event threads
+   * currently. Dont pass any value to start
+   */
+  int start(int no_of_additional_event_threads = 0, size_t stacksize = DEFAULT_STACKSIZE) override;
+
+  // clear_and_start is the same start, except the persistent database is cleared first.
+  int clear_and_start(int no_of_additional_event_threads = 0, size_t stacksize = DEFAULT_STACKSIZE);
+
+  // Private
+  HostDBCache *cache();
+
+private:
+  int init();
+
+  Action *getby(Continuation *cont, cb_process_result_pfn cb_process_result, HostDBHash &hash, Options const &opt);
+};
+
+inline bool
+HostDBRecord::is_srv() const
+{
+  return HostDBType::SRV == record_type;
+}
+
+inline char const *
+HostDBRecord::name() const
+{
+  return this->apply_offset<char const>(sizeof(self_type));
+}
+
+inline swoc::TextView
+HostDBRecord::name_view() const
+{
+  return {this->name(), swoc::TextView::npos};
+}
+
+inline ts_time
+HostDBRecord::expiry_time() const
+{
+  return ip_timestamp + ip_timeout_interval + ts_seconds(hostdb_serve_stale_but_revalidate);
+}
+
+inline ts_seconds
+HostDBRecord::ip_age() const
+{
+  static constexpr ts_seconds ZERO{0};
+  static constexpr ts_seconds MAX{0x7FFFFFFF};
+
+  return std::clamp(std::chrono::duration_cast<ts_seconds>(hostdb_current_timestamp.load() - ip_timestamp), ZERO, MAX);
+}
+
+inline ts_seconds
+HostDBRecord::ip_time_remaining() const
+{
+  static constexpr ts_seconds ZERO{0};
+  static constexpr ts_seconds MAX{0x7FFFFFFF};
+  return std::clamp(std::chrono::duration_cast<ts_seconds>(ip_timeout_interval - this->ip_age()), ZERO, MAX);
+}
+
+inline bool
+HostDBRecord::is_ip_configured_stale() const
+{
+  return (
+    ((ip_timeout_interval >= ts_seconds(2 * hostdb_ip_stale_interval)) && (ip_age() >= ts_seconds(hostdb_ip_stale_interval))));
+}
+
+inline bool
+HostDBRecord::is_ip_timeout() const
+{
+  return ip_age() >= ip_timeout_interval;
+}
+
+inline bool
+HostDBRecord::is_ip_fail_timeout() const
+{
+  return ip_age() >= ts_seconds(hostdb_ip_fail_timeout_interval);
+}
+
+inline void
+HostDBRecord::refresh_ip()
+{
+  ip_timestamp = hostdb_current_timestamp;
+}
+
+inline swoc::MemSpan<HostDBInfo>
+HostDBRecord::rr_info()
+{
+  return {this->apply_offset<HostDBInfo>(rr_offset), rr_count};
+}
+
+inline bool
+HostDBRecord::is_failed() const
+{
+  return flags.f.failed_p;
+}
+
+inline void
+HostDBRecord::set_failed()
+{
+  flags.f.failed_p = true;
+}
+
+inline unsigned short
+HostDBRecord::rr_idx() const
+{
+  return _rr_idx % rr_count;
+}
+
+inline unsigned short
+HostDBRecord::rr_idx(unsigned short delta) const
+{
+  return (_rr_idx + delta) % rr_count;
+}
+
+inline int
+HostDBRecord::index_of(HostDBInfo const *target) const
+{
+  return target ? target - this->apply_offset<HostDBInfo>(rr_offset) : -1;
+}
+
+// --
+
+inline bool
+ResolveInfo::set_active(sockaddr const *s)
+{
+  return this->set_active(record->find(s));
+}
+
+inline bool
+ResolveInfo::mark_active_server_alive()
+{
+  return active->mark_up();
+}
+
+inline bool
+ResolveInfo::mark_active_server_down(ts_time now)
+{
+  return active != nullptr && active->mark_down(now);
+}
+
+inline bool
+ResolveInfo::set_active(std::nullptr_t)
+{
+  active     = nullptr;
+  resolved_p = false;
+  return false;
+}
+
+inline bool
+ResolveInfo::set_upstream_address(sockaddr const *sa)
+{
+  return resolved_p = addr.assign(sa).isValid();
+}
+
+inline void
+ResolveInfo::set_upstream_port(in_port_t port)
+{
+  srv_port = port;
+}
+
+inline bool
+ResolveInfo::is_srv() const
+{
+  return record && record->is_srv();
+}
+// ---
+
+void run_HostDBTest();
+
+extern HostDBProcessor hostDBProcessor;
+
+void ink_hostdb_init(ts::ModuleVersion version);
diff --git a/include/iocore/hostdb/HostFile.h b/include/iocore/hostdb/HostFile.h
new file mode 100644
index 0000000000..cbc71e5d61
--- /dev/null
+++ b/include/iocore/hostdb/HostFile.h
@@ -0,0 +1,52 @@
+/** @file
+
+  HostFile class for processing a hosts file
+
+  @section license License
+
+    Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ */
+
+#pragma once
+
+#include "swoc/swoc_file.h"
+
+#include "HostDBProcessor.h"
+#include "swoc/TextView.h"
+
+#include <memory>
+#include <unordered_map>
+
+struct HostFileRecord {
+  HostDBRecord::Handle record_4;
+  HostDBRecord::Handle record_6;
+};
+
+struct HostFile {
+  using HostFileForwardMap = std::unordered_map<swoc::TextView, HostFileRecord, std::hash<std::string_view>>;
+  using HostFileReverseMap = std::unordered_map<IpAddr, HostDBRecord::Handle, IpAddr::Hasher>;
+
+  HostFile(ts_seconds ttl) : ttl(ttl) {}
+
+  HostDBRecord::Handle lookup(const HostDBHash &hash);
+
+  ts_seconds ttl;
+  HostFileForwardMap forward;
+  HostFileReverseMap reverse;
+};
+
+std::shared_ptr<HostFile> ParseHostFile(swoc::file::path const &path, ts_seconds interval);
diff --git a/iocore/io_uring/IOUringEventIO.h b/include/iocore/io_uring/IOUringEventIO.h
similarity index 100%
rename from iocore/io_uring/IOUringEventIO.h
rename to include/iocore/io_uring/IOUringEventIO.h
diff --git a/iocore/io_uring/I_IO_URING.h b/include/iocore/io_uring/IO_URING.h
similarity index 100%
rename from iocore/io_uring/I_IO_URING.h
rename to include/iocore/io_uring/IO_URING.h
diff --git a/include/iocore/net/AcceptOptions.h b/include/iocore/net/AcceptOptions.h
new file mode 100644
index 0000000000..8c26f25919
--- /dev/null
+++ b/include/iocore/net/AcceptOptions.h
@@ -0,0 +1,90 @@
+/** @file
+
+  This file implements an I/O Processor for network I/O
+
+  @section license License
+
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+ */
+
+#pragma once
+
+#include "tscore/ink_inet.h"
+
+#include "Event.h"
+
+struct AcceptOptions {
+  using self = AcceptOptions; ///< Self reference type.
+
+  /// Port on which to listen.
+  /// 0 => don't care, which is useful if the socket is already bound.
+  int local_port = 0;
+  /// Local address to bind for accept.
+  /// If not set -> any address.
+  IpAddr local_ip;
+  /// IP address family.
+  /// @note Ignored if an explicit incoming address is set in the
+  /// the configuration (@c local_ip). If neither is set IPv4 is used.
+  int ip_family = AF_INET;
+  /// Should we use accept threads? If so, how many?
+  int accept_threads = -1;
+  /** If @c true, the continuation is called back with
+      @c NET_EVENT_ACCEPT_SUCCEED
+      or @c NET_EVENT_ACCEPT_FAILED on success and failure resp.
+  */
+  bool localhost_only = false;
+  /// Are frequent accepts expected?
+  /// Default: @c false.
+  bool frequent_accept = true;
+
+  /// Socket receive buffer size.
+  /// 0 => OS default.
+  int recv_bufsize = 0;
+  /// Socket transmit buffer size.
+  /// 0 => OS default.
+  int send_bufsize = 0;
+  /// defer accept for @c sockopt.
+  /// 0 => OS default.
+  int defer_accept = 0;
+  /// Socket options for @c sockopt.
+  /// 0 => do not set options.
+  uint32_t sockopt_flags        = 0;
+  uint32_t packet_mark          = 0;
+  uint32_t packet_tos           = 0;
+  uint32_t packet_notsent_lowat = 0;
+
+  int tfo_queue_length = 0;
+
+  /** Transparency on client (user agent) connection.
+      @internal This is irrelevant at a socket level (since inbound
+      transparency must be set up when the listen socket is created)
+      but it's critical that the connection handling logic knows
+      whether the inbound (client / user agent) connection is
+      transparent.
+  */
+  bool f_inbound_transparent = false;
+
+  /** MPTCP enabled on listener.
+      @internal For logging and metrics purposes to know whether the
+      listener enabled MPTCP or not.
+  */
+  bool f_mptcp = false;
+
+  /// Proxy Protocol enabled
+  bool f_proxy_protocol = false;
+};
diff --git a/iocore/net/AsyncSignalEventIO.h b/include/iocore/net/AsyncSignalEventIO.h
similarity index 100%
rename from iocore/net/AsyncSignalEventIO.h
rename to include/iocore/net/AsyncSignalEventIO.h
diff --git a/iocore/net/BIO_fastopen.h b/include/iocore/net/BIO_fastopen.h
similarity index 100%
rename from iocore/net/BIO_fastopen.h
rename to include/iocore/net/BIO_fastopen.h
diff --git a/iocore/net/BoringSSLUtils.h b/include/iocore/net/BoringSSLUtils.h
similarity index 100%
rename from iocore/net/BoringSSLUtils.h
rename to include/iocore/net/BoringSSLUtils.h
diff --git a/iocore/net/EventIO.h b/include/iocore/net/EventIO.h
similarity index 100%
rename from iocore/net/EventIO.h
rename to include/iocore/net/EventIO.h
diff --git a/include/iocore/net/Net.h b/include/iocore/net/Net.h
new file mode 100644
index 0000000000..d24f29f910
--- /dev/null
+++ b/include/iocore/net/Net.h
@@ -0,0 +1,91 @@
+/** @file
+
+  Net subsystem
+
+  @section license License
+
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  @section details Details
+
+  Net subsystem is a layer on top the operations system network apis. It
+  provides an interface for accepting/creating new connection oriented
+  (TCP) and connection less (UDP) connections and for reading/writing
+  data through these. The net system can manage 1000s of connections
+  very efficiently. Another advantage of using the net system is that
+  the SMs dont have be concerned about differences in the net apis of
+  various operations systems.
+
+  SMs use the netProcessor global object of the Net System to create new
+  connections or to accept incoming connections. When a new connection
+  is created the SM gets a NetVConnection which is a handle for the
+  underlying connections. The SM can then use the NetVConnection to get
+  properties of the connection, read and write data. Net system also
+  has socks and ssl support.
+
+ */
+#pragma once
+
+#include "tscore/Version.h"
+#include "EventSystem.h"
+#include <netinet/in.h>
+
+#ifndef UIO_MAXIOV
+#define NET_MAX_IOV 16 // UIO_MAXIOV shall be at least 16 1003.1g (5.4.1.1)
+#else
+#define NET_MAX_IOV UIO_MAXIOV
+#endif
+
+static constexpr ts::ModuleVersion NET_SYSTEM_MODULE_PUBLIC_VERSION(1, 0, ts::ModuleVersion::PUBLIC);
+
+static constexpr int NO_FD = -1;
+
+// All in milli-seconds
+extern int net_event_period;
+extern int net_accept_period;
+extern int net_retry_delay;
+extern int net_throttle_delay;
+
+extern std::string_view net_ccp_in;
+extern std::string_view net_ccp_out;
+
+#define NET_EVENT_OPEN                    (NET_EVENT_EVENTS_START)
+#define NET_EVENT_OPEN_FAILED             (NET_EVENT_EVENTS_START + 1)
+#define NET_EVENT_ACCEPT                  (NET_EVENT_EVENTS_START + 2)
+#define NET_EVENT_ACCEPT_SUCCEED          (NET_EVENT_EVENTS_START + 3)
+#define NET_EVENT_ACCEPT_FAILED           (NET_EVENT_EVENTS_START + 4)
+#define NET_EVENT_CANCEL                  (NET_EVENT_EVENTS_START + 5)
+#define NET_EVENT_DATAGRAM_READ_COMPLETE  (NET_EVENT_EVENTS_START + 6)
+#define NET_EVENT_DATAGRAM_READ_ERROR     (NET_EVENT_EVENTS_START + 7)
+#define NET_EVENT_DATAGRAM_WRITE_COMPLETE (NET_EVENT_EVENTS_START + 8)
+#define NET_EVENT_DATAGRAM_WRITE_ERROR    (NET_EVENT_EVENTS_START + 9)
+#define NET_EVENT_DATAGRAM_READ_READY     (NET_EVENT_EVENTS_START + 10)
+#define NET_EVENT_DATAGRAM_OPEN           (NET_EVENT_EVENTS_START + 11)
+#define NET_EVENT_DATAGRAM_ERROR          (NET_EVENT_EVENTS_START + 12)
+#define NET_EVENT_ACCEPT_INTERNAL         (NET_EVENT_EVENTS_START + 22)
+#define NET_EVENT_CONNECT_INTERNAL        (NET_EVENT_EVENTS_START + 23)
+
+#define MAIN_ACCEPT_PORT -1
+
+/*
+ * Net system uses event threads
+ * so, the net thread group id is the event thread group id
+ */
+
+#define ET_NET ET_CALL
+
+void ink_net_init(ts::ModuleVersion version);
diff --git a/iocore/net/NetAcceptEventIO.h b/include/iocore/net/NetAcceptEventIO.h
similarity index 100%
rename from iocore/net/NetAcceptEventIO.h
rename to include/iocore/net/NetAcceptEventIO.h
diff --git a/include/iocore/net/NetEvent.h b/include/iocore/net/NetEvent.h
new file mode 100644
index 0000000000..33d767a2dc
--- /dev/null
+++ b/include/iocore/net/NetEvent.h
@@ -0,0 +1,141 @@
+/** @file
+
+  A brief file description
+
+  @section license License
+
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ */
+
+#pragma once
+
+#include <atomic>
+
+#include "EventSystem.h"
+#include "P_UnixNetState.h"
+#include "EventIO.h"
+#include "ReadWriteEventIO.h"
+
+class NetHandler;
+
+// this class is used to NetHandler to hide some detail of NetEvent.
+// To combine the `UDPConenction` and `NetEvent`. NetHandler should
+// callback to net_read_io or net_write_io when net event happen.
+class NetEvent
+{
+public:
+  NetEvent() = default;
+  virtual ~NetEvent() {}
+  virtual void net_read_io(NetHandler *nh, EThread *lthread)  = 0;
+  virtual void net_write_io(NetHandler *nh, EThread *lthread) = 0;
+  virtual void free_thread(EThread *t)                        = 0;
+
+  // since we want this class to be independent from VConnection, Continutaion. There should be
+  // a pure virtual function which connect sub class and NetHandler.
+  virtual int callback(int event = CONTINUATION_EVENT_NONE, void *data = nullptr) = 0;
+
+  // Duplicate with `NetVConnection::set_inactivity_timeout`
+  // TODO: more abstraction.
+  virtual void set_inactivity_timeout(ink_hrtime timeout_in)         = 0;
+  virtual void set_default_inactivity_timeout(ink_hrtime timeout_in) = 0;
+  virtual bool is_default_inactivity_timeout()                       = 0;
+
+  // get this vc's thread
+  virtual EThread *get_thread() = 0;
+
+  // Close when EventIO close;
+  virtual int close() = 0;
+
+  bool has_error() const;
+  void set_error_from_socket();
+
+  // get fd
+  virtual int get_fd()                   = 0;
+  virtual Ptr<ProxyMutex> &get_mutex()   = 0;
+  virtual ContFlags &get_control_flags() = 0;
+
+  ReadWriteEventIO ep{};
+  NetState read{};
+  NetState write{};
+
+  int closed     = 0;
+  int error      = 0;
+  NetHandler *nh = nullptr;
+
+  /** The explicitly set inactivity timeout duration in seconds.
+   *
+   * 0 means no timeout.
+   */
+  ink_hrtime inactivity_timeout_in = 0;
+
+  /** The fallback inactivity timeout which is applied if no other timeouts are
+   * set. That is, this timeout is used if inactivity_timeout_in is 0.
+   *
+   * A value of 0 means no timeout. A value of -1 means that no default timeout
+   * has been set yet. This is initialized to -1 instead of 0 so that the
+   * inactivity cop can distinguish between no value having been set and a
+   * value of 0 having been set by some override plugin.
+   */
+  std::atomic<ink_hrtime> default_inactivity_timeout_in = -1;
+
+  /** The active timeout duration in seconds. */
+  ink_hrtime active_timeout_in = 0;
+
+  /** The time of the next inactivity timeout. */
+  ink_hrtime next_inactivity_timeout_at = 0;
+
+  /** The time of the next activity timeout. */
+  ink_hrtime next_activity_timeout_at = 0;
+  ink_hrtime submit_time              = 0;
+
+  /** Whether the current timeout is a default inactivity timeout. */
+  bool use_default_inactivity_timeout = false;
+
+  LINK(NetEvent, open_link);
+  LINK(NetEvent, cop_link);
+  LINKM(NetEvent, read, ready_link)
+  SLINKM(NetEvent, read, enable_link)
+  LINKM(NetEvent, write, ready_link)
+  SLINKM(NetEvent, write, enable_link)
+  LINK(NetEvent, keep_alive_queue_link);
+  LINK(NetEvent, active_queue_link);
+
+  /// Values for @a f.shutdown
+  static constexpr unsigned SHUTDOWN_READ  = 1;
+  static constexpr unsigned SHUTDOWN_WRITE = 2;
+
+  union {
+    unsigned int flags = 0;
+    struct {
+      unsigned int got_local_addr : 1;
+      unsigned int shutdown       : 2;
+    } f;
+  };
+};
+
+inline bool
+NetEvent::has_error() const
+{
+  return error != 0;
+}
+
+inline void
+NetEvent::set_error_from_socket()
+{
+  socklen_t errlen = sizeof(error);
+  getsockopt(this->get_fd(), SOL_SOCKET, SO_ERROR, (void *)&error, &errlen);
+}
diff --git a/include/iocore/net/NetHandler.h b/include/iocore/net/NetHandler.h
new file mode 100644
index 0000000000..1e953b92b3
--- /dev/null
+++ b/include/iocore/net/NetHandler.h
@@ -0,0 +1,236 @@
+/** @file
+
+  A brief file description
+
+  @section license License
+
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ */
+
+#pragma once
+
+#include "Continuation.h"
+#include "EThread.h"
+#include "NetEvent.h"
+
+//
+// NetHandler
+//
+// A NetHandler handles the Network IO operations.  It maintains
+// lists of operations at multiples of it's periodicity.
+//
+
+/**
+  NetHandler is the processor of NetEvent for the Net sub-system. The NetHandler
+  is the core component of the Net sub-system. Once started, it is responsible
+  for polling socket fds and perform the I/O tasks in NetEvent.
+
+  The NetHandler is executed periodically to perform read/write tasks for
+  NetVConnection. The NetHandler::mainNetEvent() should be viewed as a part of
+  EThread::execute() loop. This is the reason that Net System is a sub-system.
+
+  By get_NetHandler(this_ethread()), you can get the NetHandler object that
+  runs inside the current EThread and then @c startIO / @c stopIO which
+  assign/release a NetEvent to/from NetHandler. Before you call these functions,
+  holding the mutex of this NetHandler is required.
+
+  The NetVConnection provides a set of do_io functions through which you can
+  specify continuations to be called back by its NetHandler. These function
+  calls do not block. Instead they return an VIO object and schedule the
+  callback to the continuation passed in when there are I/O events occurred.
+
+  Multi-thread scheduler:
+
+  The NetHandler should be viewed as multi-threaded schedulers which process
+  NetEvents from their queues. If vc wants to be managed by NetHandler, the vc
+  should be derived from NetEvent. The vc can be made of NetProcessor
+  (allocate_vc) either by directly adding a NetEvent to the queue
+  (NetHandler::startIO), or more conveniently, calling a method service call
+  (NetProcessor::connect_re) which synthesizes the NetEvent and places it in the
+  queue.
+
+  Callback event codes:
+
+  These event codes for do_io_read and reenable(read VIO) task:
+    VC_EVENT_READ_READY, VC_EVENT_READ_COMPLETE,
+    VC_EVENT_EOS, VC_EVENT_ERROR
+
+  These event codes for do_io_write and reenable(write VIO) task:
+    VC_EVENT_WRITE_READY, VC_EVENT_WRITE_COMPLETE
+    VC_EVENT_ERROR
+
+  There is no event and callback for do_io_shutdown / do_io_close task.
+
+  NetVConnection allocation policy:
+
+  VCs are allocated by the NetProcessor and deallocated by NetHandler.
+  A state machine may access the returned, non-recurring NetEvent / VIO until
+  it is closed by do_io_close. For recurring NetEvent, the NetEvent may be
+  accessed until it is closed. Once the NetEvent is closed, it's the
+  NetHandler's responsibility to deallocate it.
+
+  Before assign to NetHandler or after release from NetHandler, it's the
+  NetEvent's responsibility to deallocate itself.
+
+ */
+class NetHandler : public Continuation, public EThread::LoopTailHandler
+{
+  using self_type = NetHandler; ///< Self reference type.
+public:
+  // @a thread and @a trigger_event are redundant - you can get the former from
+  // the latter. If we don't get rid of @a trigger_event we should remove @a
+  // thread.
+  EThread *thread      = nullptr;
+  Event *trigger_event = nullptr;
+  QueM(NetEvent, NetState, read, ready_link) read_ready_list;
+  QueM(NetEvent, NetState, write, ready_link) write_ready_list;
+  Que(NetEvent, open_link) open_list;
+  DList(NetEvent, cop_link) cop_list;
+  ASLLM(NetEvent, NetState, read, enable_link) read_enable_list;
+  ASLLM(NetEvent, NetState, write, enable_link) write_enable_list;
+  Que(NetEvent, keep_alive_queue_link) keep_alive_queue;
+  uint32_t keep_alive_queue_size = 0;
+  Que(NetEvent, active_queue_link) active_queue;
+  uint32_t active_queue_size = 0;
+
+  /// configuration settings for managing the active and keep-alive queues
+  struct Config {
+    uint32_t max_connections_in                 = 0;
+    uint32_t max_requests_in                    = 0;
+    uint32_t inactive_threshold_in              = 0;
+    uint32_t transaction_no_activity_timeout_in = 0;
+    uint32_t keep_alive_no_activity_timeout_in  = 0;
+    uint32_t default_inactivity_timeout         = 0;
+    uint32_t additional_accepts                 = 0;
+
+    /** Return the address of the first value in this struct.
+
+        Doing updates is much easier if we treat this config struct as an array.
+        Making it a method means the knowledge of which member is the first one
+        is localized to this struct, not scattered about.
+     */
+    uint32_t &
+    operator[](int n)
+    {
+      return *(&max_connections_in + n);
+    }
+  };
+  /** Static global config, set and updated per process.
+
+      This is updated asynchronously and then events are sent to the NetHandler
+     instances per thread to copy to the per thread config at a convenient time.
+     Because these are updated independently from the command line, the update
+     events just copy a single value from the global to the local. This
+     mechanism relies on members being identical types.
+  */
+  static Config global_config;
+  Config config; ///< Per thread copy of the @c global_config
+  // Active and keep alive queue values that depend on other configuration
+  // values. These are never updated directly, they are computed from other
+  // config values.
+  uint32_t max_connections_per_thread_in = 0;
+  uint32_t max_requests_per_thread_in    = 0;
+  /// Number of configuration items in @c Config.
+  static constexpr int CONFIG_ITEM_COUNT = sizeof(Config) / sizeof(uint32_t);
+  /// Which members of @c Config the per thread values depend on.
+  /// If one of these is updated, the per thread values must also be updated.
+  static const std::bitset<CONFIG_ITEM_COUNT> config_value_affects_per_thread_value;
+  /// Set of thread types in which nethandlers are active.
+  /// This enables signaling the correct instances when the configuration is
+  /// updated. Event type threads that use @c NetHandler must set the
+  /// corresponding bit.
+  static std::bitset<std::numeric_limits<unsigned int>::digits> active_thread_types;
+
+  int mainNetEvent(int event, Event *data);
+  int waitForActivity(ink_hrtime timeout) override;
+  void process_enabled_list();
+  void process_ready_list();
+  void manage_keep_alive_queue();
+  bool manage_active_queue(NetEvent *ne, bool ignore_queue_size);
+  void add_to_keep_alive_queue(NetEvent *ne);
+  void remove_from_keep_alive_queue(NetEvent *ne);
+  bool add_to_active_queue(NetEvent *ne);
+  void remove_from_active_queue(NetEvent *ne);
+  int get_additional_accepts();
+
+  /// Per process initialization logic.
+  static void init_for_process();
+  /// Update configuration values that are per thread and depend on other
+  /// configuration values.
+  void configure_per_thread_values();
+
+  /**
+    Start to handle read & write event on a NetEvent.
+    Initial the socket fd of ne for polling system.
+    Only be called when holding the mutex of this NetHandler.
+
+    @param ne NetEvent to be managed by this NetHandler.
+    @return 0 on success, ne->nh set to this NetHandler.
+            -ERRNO on failure.
+   */
+  int startIO(NetEvent *ne);
+  /**
+    Stop to handle read & write event on a NetEvent.
+    Remove the socket fd of ne from polling system.
+    Only be called when holding the mutex of this NetHandler and must call
+    stopCop(ne) first.
+
+    @param ne NetEvent to be released.
+    @return ne->nh set to nullptr.
+   */
+  void stopIO(NetEvent *ne);
+
+  /**
+    Start to handle active timeout and inactivity timeout on a NetEvent.
+    Put the ne into open_list. All NetEvents in the open_list is checked for
+    timeout by InactivityCop. Only be called when holding the mutex of this
+    NetHandler and must call startIO(ne) first.
+
+    @param ne NetEvent to be managed by InactivityCop
+   */
+  void startCop(NetEvent *ne);
+  /**
+    Stop to handle active timeout and inactivity on a NetEvent.
+    Remove the ne from open_list and cop_list.
+    Also remove the ne from keep_alive_queue and active_queue if its context is
+    IN. Only be called when holding the mutex of this NetHandler.
+
+    @param ne NetEvent to be released.
+   */
+  void stopCop(NetEvent *ne);
+
+  // Signal the epoll_wait to terminate.
+  void signalActivity() override;
+
+  /**
+    Release a ne and free it.
+
+    @param ne NetEvent to be detached.
+   */
+  void free_netevent(NetEvent *ne);
+
+  NetHandler();
+
+  inline static DbgCtl dbg_ctl_socket{"socket"};
+  inline static DbgCtl dbg_ctl_iocore_net{"iocore_net"};
+
+private:
+  void _close_ne(NetEvent *ne, ink_hrtime now, int &handle_event, int &closed, int &total_idle_time, int &total_idle_count);
+
+  /// Static method used as the callback for runtime configuration updates.
+  static int update_nethandler_config(const char *name, RecDataT, RecData data, void *);
+};
diff --git a/include/iocore/net/NetProcessor.h b/include/iocore/net/NetProcessor.h
new file mode 100644
index 0000000000..154195e5b9
--- /dev/null
+++ b/include/iocore/net/NetProcessor.h
@@ -0,0 +1,184 @@
+/** @file
+
+  This file implements an I/O Processor for network I/O
+
+  @section license License
+
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+ */
+
+#pragma once
+
+#include "EventSystem.h"
+#include "Socks.h"
+#include "NetVConnection.h"
+#include "AcceptOptions.h"
+struct socks_conf_struct;
+#define NET_CONNECT_TIMEOUT 30
+
+struct NetVCOptions;
+
+/**
+  This is the heart of the Net system. Provides common network APIs,
+  like accept, connect etc. It performs network I/O on behalf of a
+  state machine.
+
+*/
+class NetProcessor : public Processor
+{
+public:
+  /** Options for @c accept.
+   */
+  using AcceptOptions = ::AcceptOptions;
+
+  /**
+    Accept connections on a port.
+
+    Callbacks:
+      - cont->handleEvent( NET_EVENT_ACCEPT, NetVConnection *) is
+        called for each new connection
+      - cont->handleEvent(EVENT_ERROR,-errno) on a bad error
+
+    Re-entrant callbacks (based on callback_on_open flag):
+      - cont->handleEvent(NET_EVENT_ACCEPT_SUCCEED, 0) on successful
+        accept init
+      - cont->handleEvent(NET_EVENT_ACCEPT_FAILED, 0) on accept
+        init failure
+
+    @param cont Continuation to be called back with events this
+      continuation is not locked on callbacks and so the handler must
+      be re-entrant.
+    @param opt Accept options.
+    @return Action, that can be cancelled to cancel the accept. The
+      port becomes free immediately.
+   */
+  virtual Action *accept(Continuation *cont, AcceptOptions const &opt = DEFAULT_ACCEPT_OPTIONS) = 0;
+
+  /**
+    Accepts incoming connections on port. Accept connections on port.
+    Accept is done on all net threads and throttle limit is imposed
+    if frequent_accept flag is true. This is similar to the accept
+    method described above. The only difference is that the list
+    of parameter that is takes is limited.
+
+    Callbacks:
+      - cont->handleEvent( NET_EVENT_ACCEPT, NetVConnection *) is called for each new connection
+      - cont->handleEvent(EVENT_ERROR,-errno) on a bad error
+
+    Re-entrant callbacks (based on callback_on_open flag):
+      - cont->handleEvent(NET_EVENT_ACCEPT_SUCCEED, 0) on successful accept init
+      - cont->handleEvent(NET_EVENT_ACCEPT_FAILED, 0) on accept init failure
+
+    @param cont Continuation to be called back with events this
+      continuation is not locked on callbacks and so the handler must
+      be re-entrant.
+    @param listen_socket_in if passed, used for listening.
+    @param opt Accept options.
+    @return Action, that can be cancelled to cancel the accept. The
+      port becomes free immediately.
+
+  */
+  virtual Action *main_accept(Continuation *cont, SOCKET listen_socket_in, AcceptOptions const &opt = DEFAULT_ACCEPT_OPTIONS) = 0;
+
+  virtual void stop_accept() = 0;
+
+  /**
+    Open a NetVConnection for connection oriented I/O. Connects
+    through sockserver if netprocessor is configured to use socks
+    or is socks parameters to the call are set.
+
+    Re-entrant callbacks:
+      - On success calls: c->handleEvent(NET_EVENT_OPEN, NetVConnection *)
+      - On failure calls: c->handleEvent(NET_EVENT_OPEN_FAILED, -errno)
+
+    @note Connection may not have been established when cont is
+      call back with success. If this behaviour is desired use
+      synchronous connect connet_s method.
+
+    @param cont Continuation to be called back with events.
+    @param addr target address and port to connect to.
+    @param options @see NetVCOptions.
+
+  */
+  virtual Action *connect_re(Continuation *cont, sockaddr const *addr, NetVCOptions const &options) = 0;
+
+  /**
+    Initializes the net processor. This must be called before the event threads are started.
+
+  */
+  virtual void init() = 0;
+
+  virtual void init_socks() = 0;
+
+  virtual NetVConnection *allocate_vc(EThread *) = 0;
+
+  /** Private constructor. */
+  NetProcessor(){};
+
+  /** Private destructor. */
+  ~NetProcessor() override{};
+
+  /** This is MSS for connections we accept (client connections). */
+  static int accept_mss;
+
+  //
+  // The following are required by the SOCKS protocol:
+  //
+  // Either the configuration variables will give your a regular
+  // expression for all the names that are to go through the SOCKS
+  // server, or will give you a list of domain names which should *not* go
+  // through SOCKS. If the SOCKS option is set to false then, these
+  // variables (regular expression or list) should be set
+  // appropriately. If it is set to TRUE then, in addition to supplying
+  // the regular expression or the list, the user should also give the
+  // the ip address and port number for the SOCKS server (use
+  // appropriate defaults)
+
+  /* shared by regular netprocessor and ssl netprocessor */
+  static socks_conf_struct *socks_conf_stuff;
+
+  /// Default options instance.
+  static AcceptOptions const DEFAULT_ACCEPT_OPTIONS;
+
+  // noncopyable
+  NetProcessor(const NetProcessor &)            = delete;
+  NetProcessor &operator=(const NetProcessor &) = delete;
+};
+
+/**
+  Global NetProcessor singleton object for making net calls. All
+  net processor calls like connect, accept, etc are made using this
+  object.
+
+  @code
+    netProcessor.accept(my_cont, ...);
+    netProcessor.connect_re(my_cont, ...);
+  @endcode
+
+*/
+extern NetProcessor &netProcessor;
+
+/**
+  Global netProcessor singleton object for making ssl enabled net
+  calls. As far as the SM is concerned this behaves exactly like
+  netProcessor. The only difference is that the connections are
+  over ssl.
+
+*/
+extern NetProcessor &sslNetProcessor;
+extern NetProcessor &quicNetProcessor;
diff --git a/include/iocore/net/NetTimeout.h b/include/iocore/net/NetTimeout.h
new file mode 100644
index 0000000000..904c76d637
--- /dev/null
+++ b/include/iocore/net/NetTimeout.h
@@ -0,0 +1,263 @@
+/** @file
+
+  NetTimeout
+
+  @section license License
+
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ */
+
+#pragma once
+
+#include "tscore/List.h"
+#include "tscore/ink_hrtime.h"
+
+#include "EventSystem.h"
+
+/**
+  NetTimeout - handle active & inactive timeout
+ */
+class NetTimeout
+{
+public:
+  void set_active_timeout(ink_hrtime timeout_in);
+  void set_inactive_timeout(ink_hrtime timeout_in);
+  void cancel_active_timeout();
+  void cancel_inactive_timeout();
+  void reset_active_timeout();
+  void reset_inactive_timeout();
+  bool is_active_timeout_expired(ink_hrtime now);
+  bool is_inactive_timeout_expired(ink_hrtime now);
+  ink_hrtime idle_time(ink_hrtime now);
+  void update_inactivity();
+
+private:
+  ink_hrtime _active_timeout_in        = 0;
+  ink_hrtime _inactive_timeout_in      = 0;
+  ink_hrtime _next_active_timeout_at   = 0;
+  ink_hrtime _next_inactive_timeout_at = 0;
+};
+
+/**
+  ActivityCop - Check activity of T in the List in every @f seconds
+
+  T have to handle VC_EVENT_ACTIVE_TIMEOUT and VC_EVENT_INACTIVITY_TIMEOUT events.
+
+  TODO: add concepts like below with C++20
+  ```
+  template <class T, class List = DLL<T>>
+  concept Timeoutable = requires(T *t, List *list, ink_hrtime time) {
+    t->handleEvent();
+    t->head;
+    {list->next(t)} -> std::convertible_to<T *>;
+    {t->is_active_timeout_expired(time)} -> std::same_as<bool>;
+    {t->is_inactive_timeout_expired(time)} -> std::same_as<bool>;
+  };
+  ```
+ */
+template <class T, class List = DLL<T>> class ActivityCop : public Continuation
+{
+public:
+  ActivityCop(){};
+  ActivityCop(Ptr<ProxyMutex> &m, List *l, int f);
+
+  void start();
+  void stop();
+  int check_activity(int event, Event *e);
+
+private:
+  Event *_event = nullptr;
+  List *_list   = nullptr;
+  int _freq     = 1;
+};
+
+////
+// Inline functions
+
+//
+// NetTimeout
+//
+inline void
+NetTimeout::set_active_timeout(ink_hrtime timeout_in)
+{
+  if (timeout_in == 0) {
+    return;
+  }
+
+  _active_timeout_in      = timeout_in;
+  _next_active_timeout_at = ink_get_hrtime() + timeout_in;
+}
+
+inline void
+NetTimeout::set_inactive_timeout(ink_hrtime timeout_in)
+{
+  if (timeout_in == 0) {
+    return;
+  }
+
+  _inactive_timeout_in      = timeout_in;
+  _next_inactive_timeout_at = ink_get_hrtime() + timeout_in;
+}
+
+inline void
+NetTimeout::cancel_active_timeout()
+{
+  _active_timeout_in      = 0;
+  _next_active_timeout_at = 0;
+}
+
+inline void
+NetTimeout::cancel_inactive_timeout()
+{
+  _inactive_timeout_in      = 0;
+  _next_inactive_timeout_at = 0;
+}
+
+inline void
+NetTimeout::reset_active_timeout()
+{
+  if (_active_timeout_in == 0) {
+    return;
+  }
+
+  _next_active_timeout_at = ink_get_hrtime() + _active_timeout_in;
+}
+
+inline void
+NetTimeout::reset_inactive_timeout()
+{
+  if (_inactive_timeout_in == 0) {
+    return;
+  }
+
+  _next_inactive_timeout_at = ink_get_hrtime() + _inactive_timeout_in;
+}
+
+inline bool
+NetTimeout::is_active_timeout_expired(ink_hrtime now)
+{
+  ink_assert(now > 0);
+
+  if (_active_timeout_in == 0) {
+    return false;
+  }
+
+  if (0 < _next_active_timeout_at && _next_active_timeout_at < now) {
+    Debug("activity_cop", "active timeout cont=%p now=%" PRId64 " timeout_at=%" PRId64 " timeout_in=%" PRId64, this,
+          ink_hrtime_to_sec(now), ink_hrtime_to_sec(_next_active_timeout_at), ink_hrtime_to_sec(_active_timeout_in));
+    return true;
+  }
+
+  return false;
+}
+
+inline bool
+NetTimeout::is_inactive_timeout_expired(ink_hrtime now)
+{
+  ink_assert(now > 0);
+
+  if (_inactive_timeout_in == 0) {
+    return false;
+  }
+
+  if (0 < _next_inactive_timeout_at && _next_inactive_timeout_at < now) {
+    Debug("activity_cop", "inactive timeout cont=%p now=%" PRId64 " timeout_at=%" PRId64 " timeout_in=%" PRId64, this,
+          ink_hrtime_to_sec(now), ink_hrtime_to_sec(_next_inactive_timeout_at), ink_hrtime_to_sec(_inactive_timeout_in));
+    return true;
+  }
+
+  return false;
+}
+
+/**
+  Return how log this was inactive.
+ */
+inline ink_hrtime
+NetTimeout::idle_time(ink_hrtime now)
+{
+  if (now < _next_inactive_timeout_at) {
+    return 0;
+  }
+
+  return ink_hrtime_to_sec((now - _next_inactive_timeout_at) + _inactive_timeout_in);
+}
+
+inline void
+NetTimeout::update_inactivity()
+{
+  if (_inactive_timeout_in == 0) {
+    return;
+  }
+
+  _next_inactive_timeout_at = ink_get_hrtime() + _inactive_timeout_in;
+}
+
+//
+// ActivityCop
+//
+template <class T, class List>
+inline ActivityCop<T, List>::ActivityCop(Ptr<ProxyMutex> &m, List *l, int f) : Continuation(m.get()), _list(l), _freq(f)
+{
+  SET_HANDLER((&ActivityCop<T, List>::check_activity));
+}
+
+template <class T, class List>
+inline void
+ActivityCop<T, List>::start()
+{
+  _event = this_ethread()->schedule_every(this, HRTIME_SECONDS(_freq));
+}
+
+template <class T, class List>
+inline void
+ActivityCop<T, List>::stop()
+{
+  _event->cancel();
+}
+
+template <class T, class List>
+inline int
+ActivityCop<T, List>::check_activity(int /* event */, Event *e)
+{
+  ink_hrtime now = ink_get_hrtime();
+
+  // Traverse list & check inactivity or activity
+  T *t = _list->head;
+  while (t) {
+    T *next = _list->next(t);
+    if (t->mutex == nullptr) {
+      t = next;
+      continue;
+    }
+
+    MUTEX_TRY_LOCK(lock, t->mutex, this_ethread());
+    if (!lock.is_locked()) {
+      t = next;
+      continue;
+    }
+
+    if (t->is_inactive_timeout_expired(now)) {
+      t->handleEvent(VC_EVENT_INACTIVITY_TIMEOUT, e);
+    } else if (t->is_active_timeout_expired(now)) {
+      t->handleEvent(VC_EVENT_ACTIVE_TIMEOUT, e);
+    }
+
+    t = next;
+  }
+
+  return EVENT_DONE;
+}
diff --git a/include/iocore/net/NetVCOptions.h b/include/iocore/net/NetVCOptions.h
new file mode 100644
index 0000000000..d2d8eba879
--- /dev/null
+++ b/include/iocore/net/NetVCOptions.h
@@ -0,0 +1,318 @@
+/** @file
+
+  NetVConnection options class
+
+  @section license License
+
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+ */
+#pragma once
+#include "tscore/ink_inet.h"
+#include "EventSystem.h"
+#include "Event.h"
+#include "YamlSNIConfig.h"
+
+#include <cstdint>
+
+struct NetVCOptions {
+  using self = NetVCOptions; ///< Self reference type.
+
+  /// Values for valid IP protocols.
+  enum ip_protocol_t {
+    USE_TCP, ///< TCP protocol.
+    USE_UDP  ///< UDP protocol.
+  };
+
+  /// IP (TCP or UDP) protocol to use on socket.
+  ip_protocol_t ip_proto;
+
+  /** IP address family.
+
+      This is used for inbound connections only if @c local_ip is not
+      set, which is sometimes more convenient for the client. This
+      defaults to @c AF_INET so if the client sets neither this nor @c
+      local_ip then IPv4 is used.
+
+      For outbound connections this is ignored and the family of the
+      remote address used.
+
+      @note This is (inconsistently) called "domain" and "protocol" in
+      other places. "family" is used here because that's what the
+      standard IP data structures use.
+
+  */
+  uint16_t ip_family;
+
+  /** The set of ways in which the local address should be bound.
+
+      The protocol is set by the contents of @a local_addr regardless
+      of this value. @c ANY_ADDR will override only the address.
+
+      @note The difference between @c INTF_ADDR and @c FOREIGN_ADDR is
+      whether transparency is enabled on the socket. It is the
+      client's responsibility to set this correctly based on whether
+      the address in @a local_addr is associated with an interface on
+      the local system ( @c INTF_ADDR ) or is owned by a foreign
+      system ( @c FOREIGN_ADDR ).  A binding style of @c ANY_ADDR
+      causes the value in @a local_addr to be ignored.
+
+      The IP address and port are separate because most clients treat
+      these independently. For the same reason @c IpAddr is used
+      to be clear that it contains no port data.
+
+      @see local_addr
+      @see addr_binding
+   */
+  enum addr_bind_style {
+    ANY_ADDR,    ///< Bind to any available local address (don't care, default).
+    INTF_ADDR,   ///< Bind to interface address in @a local_addr.
+    FOREIGN_ADDR ///< Bind to foreign address in @a local_addr.
+  };
+
+  /** Local address for the connection.
+
+      For outbound connections this must have the same family as the
+      remote address (which is not stored in this structure). For
+      inbound connections the family of this value overrides @a
+      ip_family if set.
+
+      @note Ignored if @a addr_binding is @c ANY_ADDR.
+      @see addr_binding
+      @see ip_family
+  */
+  IpAddr local_ip;
+
+  /** Local port for connection.
+      Set to 0 for "don't care" (default).
+  */
+  uint16_t local_port;
+
+  /// How to bind the local address.
+  /// @note Default is @c ANY_ADDR.
+  addr_bind_style addr_binding;
+
+  /// Make the socket blocking on I/O (default: @c false)
+  // TODO: make this const.  We don't use blocking
+  bool f_blocking = false;
+  /// Make socket block on connect (default: @c false)
+  // TODO: make this const.  We don't use blocking
+  bool f_blocking_connect = false;
+
+  // Use TCP Fast Open on this socket. The connect(2) call will be omitted.
+  bool f_tcp_fastopen = false;
+
+  /// Control use of SOCKS.
+  /// Set to @c NO_SOCKS to disable use of SOCKS. Otherwise SOCKS is
+  /// used if available.
+  unsigned char socks_support;
+  /// Version of SOCKS to use.
+  unsigned char socks_version;
+
+  int socket_recv_bufsize;
+  int socket_send_bufsize;
+
+  /// Configuration options for sockets.
+  /// @note These are not identical to internal socket options but
+  /// specifically defined for configuration. These are mask values
+  /// and so must be powers of 2.
+  uint32_t sockopt_flags;
+  /// Value for TCP no delay for @c sockopt_flags.
+  static uint32_t const SOCK_OPT_NO_DELAY = 1;
+  /// Value for keep alive for @c sockopt_flags.
+  static uint32_t const SOCK_OPT_KEEP_ALIVE = 2;
+  /// Value for linger on for @c sockopt_flags
+  static uint32_t const SOCK_OPT_LINGER_ON = 4;
+  /// Value for TCP Fast open @c sockopt_flags
+  static uint32_t const SOCK_OPT_TCP_FAST_OPEN = 8;
+  /// Value for SO_MARK @c sockopt_flags
+  static uint32_t const SOCK_OPT_PACKET_MARK = 16;
+  /// Value for IP_TOS @c sockopt_flags
+  static uint32_t const SOCK_OPT_PACKET_TOS = 32;
+  /// Value for TCP_NOTSENT_LOWAT @c sockopt_flags
+  static uint32_t const SOCK_OPT_TCP_NOTSENT_LOWAT = 64;
+
+  uint32_t packet_mark;
+  uint32_t packet_tos;
+  uint32_t packet_notsent_lowat;
+
+  EventType etype;
+
+  /** ALPN protocol-lists. The format is OpenSSL protocol-lists format (vector of 8-bit length-prefixed, byte strings)
+      https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set_alpn_protos.html
+   */
+  std::string_view alpn_protos;
+  /** Server name to use for SNI data on an outbound connection.
+   */
+  ats_scoped_str sni_servername;
+  /** FQDN used to connect to the origin.  May be different
+   * than sni_servername if pristine host headers are used
+   */
+  ats_scoped_str ssl_servername;
+
+  /** Server host name from client's request to use for SNI data on an outbound connection.
+   */
+  ats_scoped_str sni_hostname;
+
+  /**
+   * Client certificate to use in response to OS's certificate request
+   */
+  ats_scoped_str ssl_client_cert_name;
+  /*
+   * File containing private key matching certificate
+   */
+  const char *ssl_client_private_key_name = nullptr;
+  /*
+   * File containing CA certs for verifying origin's cert
+   */
+  const char *ssl_client_ca_cert_name = nullptr;
+  /*
+   * Directory containing CA certs for verifying origin's cert
+   */
+  const char *ssl_client_ca_cert_path = nullptr;
+
+  bool tls_upstream = false;
+
+  unsigned char alpn_protocols_array[MAX_ALPN_STRING];
+  int alpn_protocols_array_size = 0;
+
+  /**
+   * Set to DISABLED, PERFMISSIVE, or ENFORCED
+   * Controls how the server certificate verification is handled
+   */
+  YamlSNIConfig::Policy verifyServerPolicy = YamlSNIConfig::Policy::DISABLED;
+
+  /**
+   * Bit mask of which features of the server certificate should be checked
+   * Currently SIGNATURE and NAME
+   */
+  YamlSNIConfig::Property verifyServerProperties = YamlSNIConfig::Property::NONE;
+
+  /// Reset all values to defaults.
+  void reset();
+
+  void set_sock_param(int _recv_bufsize, int _send_bufsize, unsigned long _opt_flags, unsigned long _packet_mark = 0,
+                      unsigned long _packet_tos = 0, unsigned long _packet_notsent_lowat = 0);
+
+  NetVCOptions() { reset(); }
+  ~NetVCOptions() {}
+
+  /** Set the SNI server name.
+      A local copy is made of @a name.
+  */
+  self &
+  set_sni_servername(const char *name, size_t len)
+  {
+    IpEndpoint ip;
+
+    // Literal IPv4 and IPv6 addresses are not permitted in "HostName".(rfc6066#section-3)
+    if (name && len && ats_ip_pton(std::string_view(name, len), &ip) != 0) {
+      sni_servername = ats_strndup(name, len);
+    } else {
+      sni_servername = nullptr;
+    }
+    return *this;
+  }
+
+  self &
+  set_ssl_client_cert_name(const char *name)
+  {
+    if (name) {
+      ssl_client_cert_name = ats_strdup(name);
+    } else {
+      ssl_client_cert_name = nullptr;
+    }
+    return *this;
+  }
+
+  self &
+  set_ssl_servername(const char *name)
+  {
+    if (name) {
+      ssl_servername = ats_strdup(name);
+    } else {
+      ssl_servername = nullptr;
+    }
+    return *this;
+  }
+
+  self &
+  set_sni_hostname(const char *name, size_t len)
+  {
+    IpEndpoint ip;
+
+    // Literal IPv4 and IPv6 addresses are not permitted in "HostName".(rfc6066#section-3)
+    if (name && len && ats_ip_pton(std::string_view(name, len), &ip) != 0) {
+      sni_hostname = ats_strndup(name, len);
+    } else {
+      sni_hostname = nullptr;
+    }
+    return *this;
+  }
+
+  self &
+  operator=(self const &that)
+  {
+    if (&that != this) {
+      /*
+       * It is odd but necessary to null the scoped string pointer here
+       * and then explicitly call release on them in the string assignments
+       * below.
+       * We a memcpy from that to this.  This will put that's string pointers into
+       * this's memory.  Therefore we must first explicitly null out
+       * this's original version of the string.  The release after the
+       * memcpy removes the extra reference to that's copy of the string
+       * Removing the release will eventually cause a double free crash
+       */
+      sni_servername       = nullptr; // release any current name.
+      ssl_servername       = nullptr;
+      sni_hostname         = nullptr;
+      ssl_client_cert_name = nullptr;
+      memcpy(static_cast<void *>(this), &that, sizeof(self));
+      if (that.sni_servername) {
+        sni_servername.release(); // otherwise we'll free the source string.
+        this->sni_servername = ats_strdup(that.sni_servername);
+      }
+      if (that.ssl_servername) {
+        ssl_servername.release(); // otherwise we'll free the source string.
+        this->ssl_servername = ats_strdup(that.ssl_servername);
+      }
+      if (that.sni_hostname) {
+        sni_hostname.release(); // otherwise we'll free the source string.
+        this->sni_hostname = ats_strdup(that.sni_hostname);
+      }
+      if (that.ssl_client_cert_name) {
+        this->ssl_client_cert_name.release(); // otherwise we'll free the source string.
+        this->ssl_client_cert_name = ats_strdup(that.ssl_client_cert_name);
+      }
+    }
+    return *this;
+  }
+
+  std::string_view get_family_string() const;
+
+  std::string_view get_proto_string() const;
+
+  /// @name Debugging
+  //@{
+  /// Convert @a s to its string equivalent.
+  static const char *toString(addr_bind_style s);
+  //@}
+
+  // noncopyable
+  NetVCOptions(const NetVCOptions &) = delete;
+};
diff --git a/include/iocore/net/NetVConnection.h b/include/iocore/net/NetVConnection.h
new file mode 100644
index 0000000000..757222acc4
--- /dev/null
+++ b/include/iocore/net/NetVConnection.h
@@ -0,0 +1,703 @@
+/** @file
+
+  This file implements an I/O Processor for network I/O
+
+  @section license License
+
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+ */
+#pragma once
+
+#include "NetVCOptions.h"
+#include "ProxyProtocol.h"
+#include "Net.h"
+
+#include <string_view>
+#include <optional>
+
+#include "tscore/ink_inet.h"
+#include "Action.h"
+#include "VConnection.h"
+#include "Event.h"
+#include "tscore/List.h"
+#include "IOBuffer.h"
+#include "Socks.h"
+#include "ts/apidefs.h"
+#include "YamlSNIConfig.h"
+#include "swoc/TextView.h"
+
+#define CONNECT_SUCCESS 1
+#define CONNECT_FAILURE 0
+
+#define SSL_EVENT_SERVER 0
+#define SSL_EVENT_CLIENT 1
+
+// Indicator the context for a NetVConnection
+typedef enum {
+  NET_VCONNECTION_UNSET = 0,
+  NET_VCONNECTION_IN,  // Client <--> ATS, Client-Side
+  NET_VCONNECTION_OUT, // ATS <--> Server, Server-Side
+} NetVConnectionContext_t;
+
+/**
+  A VConnection for a network socket. Abstraction for a net connection.
+  Similar to a socket descriptor VConnections are IO handles to
+  streams. In one sense, they serve a purpose similar to file
+  descriptors. Unlike file descriptors, VConnections allow for a
+  stream IO to be done based on a single read or write call.
+
+*/
+class NetVConnection : public VConnection, public PluginUserArgs<TS_USER_ARGS_VCONN>
+{
+public:
+  /**
+     Initiates read. Thread safe, may be called when not handling
+     an event from the NetVConnection, or the NetVConnection creation
+     callback.
+
+    Callbacks: non-reentrant, c's lock taken during callbacks.
+
+    <table>
+      <tr><td>c->handleEvent(VC_EVENT_READ_READY, vio)</td><td>data added to buffer</td></tr>
+      <tr><td>c->handleEvent(VC_EVENT_READ_COMPLETE, vio)</td><td>finished reading nbytes of data</td></tr>
+      <tr><td>c->handleEvent(VC_EVENT_EOS, vio)</td><td>the stream has been shutdown</td></tr>
+      <tr><td>c->handleEvent(VC_EVENT_ERROR, vio)</td><td>error</td></tr>
+    </table>
+
+    The vio returned during callbacks is the same as the one returned
+    by do_io_read(). The vio can be changed only during call backs
+    from the vconnection.
+
+    @param c continuation to be called back after (partial) read
+    @param nbytes no of bytes to read, if unknown set to INT64_MAX
+    @param buf buffer to put the data into
+    @return vio
+
+  */
+  VIO *do_io_read(Continuation *c, int64_t nbytes, MIOBuffer *buf) override = 0;
+
+  /**
+    Initiates write. Thread-safe, may be called when not handling
+    an event from the NetVConnection, or the NetVConnection creation
+    callback.
+
+    Callbacks: non-reentrant, c's lock taken during callbacks.
+
+    <table>
+      <tr>
+        <td>c->handleEvent(VC_EVENT_WRITE_READY, vio)</td>
+        <td>signifies data has written from the reader or there are no bytes available for the reader to write.</td>
+      </tr>
+      <tr>
+        <td>c->handleEvent(VC_EVENT_WRITE_COMPLETE, vio)</td>
+        <td>signifies the amount of data indicated by nbytes has been read from the buffer</td>
+      </tr>
+      <tr>
+        <td>c->handleEvent(VC_EVENT_ERROR, vio)</td>
+        <td>signified that error occurred during write.</td>
+      </tr>
+    </table>
+
+    The vio returned during callbacks is the same as the one returned
+    by do_io_write(). The vio can be changed only during call backs
+    from the vconnection. The vconnection deallocates the reader
+    when it is destroyed.
+
+    @param c continuation to be called back after (partial) write
+    @param nbytes no of bytes to write, if unknown must be set to INT64_MAX
+    @param buf source of data
+    @param owner
+    @return vio pointer
+
+  */
+  VIO *do_io_write(Continuation *c, int64_t nbytes, IOBufferReader *buf, bool owner = false) override = 0;
+
+  /**
+    Closes the vconnection. A state machine MUST call do_io_close()
+    when it has finished with a VConnection. do_io_close() indicates
+    that the VConnection can be deallocated. After a close has been
+    called, the VConnection and underlying processor must NOT send
+    any more events related to this VConnection to the state machine.
+    Likewise, state machine must not access the VConnection or
+    any returned VIOs after calling close. lerrno indicates whether
+    a close is a normal close or an abort. The difference between
+    a normal close and an abort depends on the underlying type of
+    the VConnection. Passing VIO::CLOSE for lerrno indicates a
+    normal close while passing VIO::ABORT indicates an abort.
+
+    @param lerrno VIO:CLOSE for regular close or VIO::ABORT for aborts
+
+  */
+  void do_io_close(int lerrno = -1) override = 0;
+
+  /**
+    Shuts down read side, write side, or both. do_io_shutdown() can
+    be used to terminate one or both sides of the VConnection. The
+    howto is one of IO_SHUTDOWN_READ, IO_SHUTDOWN_WRITE,
+    IO_SHUTDOWN_READWRITE. Once a side of a VConnection is shutdown,
+    no further I/O can be done on that side of the connections and
+    the underlying processor MUST NOT send any further events
+    (INCLUDING TIMEOUT EVENTS) to the state machine. The state machine
+    MUST NOT use any VIOs from a shutdown side of a connection.
+    Even if both sides of a connection are shutdown, the state
+    machine MUST still call do_io_close() when it wishes the
+    VConnection to be deallocated.
+
+    @param howto IO_SHUTDOWN_READ, IO_SHUTDOWN_WRITE, IO_SHUTDOWN_READWRITE
+
+  */
+  void do_io_shutdown(ShutdownHowTo_t howto) override = 0;
+
+  /**
+    Return the server name that is appropriate for the network VC type
+  */
+  virtual const char *
+  get_server_name() const
+  {
+    return nullptr;
+  }
+
+  ////////////////////////////////////////////////////////////
+  // Set the timeouts associated with this connection.      //
+  // active_timeout is for the total elapsed time of        //
+  // the connection.                                        //
+  // inactivity_timeout is the elapsed time from the time   //
+  // a read or a write was scheduled during which the       //
+  // connection  was unable to sink/provide data.           //
+  // calling these functions repeatedly resets the timeout. //
+  // These functions are NOT THREAD-SAFE, and may only be   //
+  // called when handing an  event from this NetVConnection,//
+  // or the NetVConnection creation callback.               //
+  ////////////////////////////////////////////////////////////
+
+  /**
+    Sets time after which SM should be notified.
+
+    Sets the amount of time (in nanoseconds) after which the state
+    machine using the NetVConnection should receive a
+    VC_EVENT_ACTIVE_TIMEOUT event. The timeout is value is ignored
+    if neither the read side nor the write side of the connection
+    is currently active. The timer is reset if the function is
+    called repeatedly This call can be used by SMs to make sure
+    that it does not keep any connections open for a really long
+    time.
+
+    Timeout semantics:
+
+    Should a timeout occur, the state machine for the read side of
+    the NetVConnection is signaled first assuming that a read has
+    been initiated on the NetVConnection and that the read side of
+    the NetVConnection has not been shutdown. Should either of the
+    two conditions not be met, the NetProcessor will attempt to
+    signal the write side. If a timeout is sent to the read side
+    state machine and its handler, return EVENT_DONE, a timeout
+    will not be sent to the write side. Should the return from the
+    handler not be EVENT_DONE and the write side state machine is
+    different (in terms of pointer comparison) from the read side
+    state machine, the NetProcessor will try to signal the write
+    side state machine as well. To signal write side, a write must
+    have been initiated on it and the write must not have been
+    shutdown.
+
+    Receiving a timeout is only a notification that the timer has
+    expired. The NetVConnection is still usable. Further timeouts
+    of the type signaled will not be generated unless the timeout
+    is reset via the set_active_timeout() or set_inactivity_timeout()
+    interfaces.
+
+  */
+  virtual void set_active_timeout(ink_hrtime timeout_in) = 0;
+
+  /**
+    Sets time after which SM should be notified if the requested
+    IO could not be performed. Sets the amount of time (in nanoseconds),
+    if the NetVConnection is idle on both the read or write side,
+    after which the state machine using the NetVConnection should
+    receive a VC_EVENT_INACTIVITY_TIMEOUT event. Either read or
+    write traffic will cause timer to be reset. Calling this function
+    again also resets the timer. The timeout is value is ignored
+    if neither the read side nor the write side of the connection
+    is currently active. See section on timeout semantics above.
+
+   */
+  virtual void set_inactivity_timeout(ink_hrtime timeout_in)         = 0;
+  virtual void set_default_inactivity_timeout(ink_hrtime timeout_in) = 0;
+  virtual bool is_default_inactivity_timeout()                       = 0;
+
+  /**
+    Clears the active timeout. No active timeouts will be sent until
+    set_active_timeout() is used to reset the active timeout.
+
+  */
+  virtual void cancel_active_timeout() = 0;
+
+  /**
+    Clears the inactivity timeout. No inactivity timeouts will be sent (aside
+    from the default inactivity timeout) until set_inactivity_timeout() is used
+    to reset the inactivity timeout.
+
+  */
+  virtual void cancel_inactivity_timeout() = 0;
+
+  /** Set the action to use a continuation.
+      The action continuation will be called with an event if there is no pending I/O operation
+      to receive the event.
+
+      Pass @c nullptr to disable.
+
+      @internal Subclasses should implement this if they support actions. This abstract class does
+      not. If the subclass doesn't have an action this method is silently ignored.
+  */
+  virtual void
+  set_action(Continuation *)
+  {
+    return;
+  }
+
+  virtual void add_to_keep_alive_queue() = 0;
+
+  virtual void remove_from_keep_alive_queue() = 0;
+
+  virtual bool add_to_active_queue() = 0;
+
+  /** @return the current active_timeout value in nanosecs */
+  virtual ink_hrtime get_active_timeout() = 0;
+
+  /** @return current inactivity_timeout value in nanosecs */
+  virtual ink_hrtime get_inactivity_timeout() = 0;
+
+  /** Force an @a event if a write operation empties the write buffer.
+
+      This event will be sent to the VIO, the same place as other IO events.
+      Use an @a event value of 0 to cancel the trap.
+
+      The event is sent only the next time the write buffer is emptied, not
+      every future time. The event is sent only if otherwise no event would
+      be generated.
+   */
+  virtual void trapWriteBufferEmpty(int event = VC_EVENT_WRITE_READY);
+
+  /** Returns local sockaddr storage. */
+  sockaddr const *get_local_addr();
+  IpEndpoint const &get_local_endpoint();
+
+  /** Returns local port. */
+  uint16_t get_local_port();
+
+  /** Returns remote sockaddr storage. */
+  sockaddr const *get_remote_addr();
+  IpEndpoint const &get_remote_endpoint();
+
+  /** Returns remote port. */
+  uint16_t get_remote_port();
+
+  /** Set the context of NetVConnection.
+   * The context is ONLY set once and will not be changed.
+   *
+   * @param context The context to be set.
+   */
+  void
+  set_context(NetVConnectionContext_t context)
+  {
+    ink_assert(NET_VCONNECTION_UNSET == netvc_context);
+    netvc_context = context;
+  }
+
+  /** Get the context.
+   * @return the context of current NetVConnection
+   */
+  NetVConnectionContext_t
+  get_context() const
+  {
+    return netvc_context;
+  }
+
+  /**
+   * Returns true if the network protocol
+   * supports a client provided SNI value
+   */
+  virtual bool
+  support_sni() const
+  {
+    return false;
+  }
+
+  virtual const char *
+  get_sni_servername() const
+  {
+    return nullptr;
+  }
+
+  virtual bool
+  peer_provided_cert() const
+  {
+    return false;
+  }
+
+  virtual int
+  provided_cert() const
+  {
+    return 0;
+  }
+
+  /** Structure holding user options. */
+  NetVCOptions options;
+
+  /** Attempt to push any changed options down */
+  virtual void apply_options() = 0;
+
+  //
+  // Private
+  //
+
+  // The following variable used to obtain host addr when transparency
+  // is enabled by SocksProxy
+  SocksAddrType socks_addr;
+
+  unsigned int attributes = 0;
+  EThread *thread         = nullptr;
+
+  /// PRIVATE: The public interface is VIO::reenable()
+  void reenable(VIO *vio) override = 0;
+
+  /// PRIVATE: The public interface is VIO::reenable()
+  void reenable_re(VIO *vio) override = 0;
+
+  /// PRIVATE
+  ~NetVConnection() override {}
+  /**
+    PRIVATE: instances of NetVConnection cannot be created directly
+    by the state machines. The objects are created by NetProcessor
+    calls like accept connect_re() etc. The constructor is public
+    just to avoid compile errors.
+
+  */
+  NetVConnection();
+
+  virtual SOCKET get_socket() = 0;
+
+  /** Set the TCP congestion control algorithm */
+  virtual int set_tcp_congestion_control(int side) = 0;
+
+  /** Set local sock addr struct. */
+  virtual void set_local_addr() = 0;
+
+  /** Set remote sock addr struct. */
+  virtual void set_remote_addr() = 0;
+
+  /** Set remote sock addr struct. */
+  virtual void set_remote_addr(const sockaddr *) = 0;
+
+  /** Set the MPTCP state for this connection */
+  virtual void set_mptcp_state() = 0;
+
+  // for InkAPI
+  bool
+  get_is_internal_request() const
+  {
+    return is_internal_request;
+  }
+
+  void
+  set_is_internal_request(bool val = false)
+  {
+    is_internal_request = val;
+  }
+
+  bool
+  get_is_unmanaged_request() const
+  {
+    return is_unmanaged_request;
+  }
+
+  void
+  set_is_unmanaged_request(bool val = false)
+  {
+    is_unmanaged_request = val;
+  }
+
+  /// Get the transparency state.
+  bool
+  get_is_transparent() const
+  {
+    return is_transparent;
+  }
+
+  /// Get the MPTCP state of the VC.
+  std::optional<bool>
+  get_mptcp_state() const
+  {
+    return mptcp_state;
+  }
+
+  /// Set the transparency state.
+  void
+  set_is_transparent(bool state = true)
+  {
+    is_transparent = state;
+  }
+
+  /// Get the proxy protocol enabled flag
+  bool
+  get_is_proxy_protocol() const
+  {
+    return is_proxy_protocol;
+  }
+  /// Set the proxy protocol enabled flag on the port
+  void
+  set_is_proxy_protocol(bool state = true)
+  {
+    is_proxy_protocol = state;
+  }
+
+  virtual int
+  populate_protocol(std::string_view *results, int n) const
+  {
+    return 0;
+  }
+
+  virtual const char *
+  protocol_contains(std::string_view prefix) const
+  {
+    return nullptr;
+  }
+
+  // noncopyable
+  NetVConnection(const NetVConnection &)            = delete;
+  NetVConnection &operator=(const NetVConnection &) = delete;
+
+  ProxyProtocolVersion
+  get_proxy_protocol_version() const
+  {
+    return pp_info.version;
+  }
+
+  sockaddr const *get_proxy_protocol_addr(const ProxyProtocolData) const;
+
+  sockaddr const *
+  get_proxy_protocol_src_addr() const
+  {
+    return get_proxy_protocol_addr(ProxyProtocolData::SRC);
+  }
+
+  uint16_t
+  get_proxy_protocol_src_port() const
+  {
+    return ats_ip_port_host_order(this->get_proxy_protocol_addr(ProxyProtocolData::SRC));
+  }
+
+  sockaddr const *
+  get_proxy_protocol_dst_addr() const
+  {
+    return get_proxy_protocol_addr(ProxyProtocolData::DST);
+  }
+
+  uint16_t
+  get_proxy_protocol_dst_port() const
+  {
+    return ats_ip_port_host_order(this->get_proxy_protocol_addr(ProxyProtocolData::DST));
+  };
+
+  void set_proxy_protocol_info(const ProxyProtocol &src);
+  const ProxyProtocol &get_proxy_protocol_info() const;
+
+  bool has_proxy_protocol(IOBufferReader *);
+  bool has_proxy_protocol(char *, int64_t *);
+
+  template <typename S> S *get_service() const;
+
+protected:
+  enum class Service : uint8_t {
+    TLS_ALPN,
+    TLS_Basic,
+    TLS_CertSwitch,
+    TLS_EarlyData,
+    TLS_SNI,
+    TLS_SessionResumption,
+    TLS_Tunnel,
+    QUIC,
+    N_SERVICES,
+  };
+
+  IpEndpoint local_addr;
+  IpEndpoint remote_addr;
+  ProxyProtocol pp_info;
+
+  bool got_local_addr  = false;
+  bool got_remote_addr = false;
+
+  bool is_internal_request  = false;
+  bool is_unmanaged_request = false;
+  /// Set if this connection is transparent.
+  bool is_transparent = false;
+  /// Set if proxy protocol is enabled
+  bool is_proxy_protocol = false;
+  /// This is essentially a tri-state, we leave it undefined to mean no MPTCP support
+  std::optional<bool> mptcp_state;
+  /// Set if the next write IO that empties the write buffer should generate an event.
+  int write_buffer_empty_event = 0;
+  /// NetVConnection Context.
+  NetVConnectionContext_t netvc_context = NET_VCONNECTION_UNSET;
+
+  template <typename S> void _set_service(S *instance);
+
+private:
+  void *_services[static_cast<unsigned int>(Service::N_SERVICES)] = {
+    nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
+  };
+
+  void *_get_service(enum Service mixin_index) const;
+  void _set_service(enum Service mixin_index, void *instance);
+};
+
+inline NetVConnection::NetVConnection() : VConnection(nullptr)
+
+{
+  ink_zero(local_addr);
+  ink_zero(remote_addr);
+}
+
+inline void
+NetVConnection::trapWriteBufferEmpty(int event)
+{
+  write_buffer_empty_event = event;
+}
+
+inline void *
+NetVConnection::_get_service(enum NetVConnection::Service service) const
+{
+  return _services[static_cast<unsigned int>(service)];
+}
+
+inline void
+NetVConnection::_set_service(enum NetVConnection::Service service, void *instance)
+{
+  this->_services[static_cast<unsigned int>(service)] = instance;
+}
+
+class ALPNSupport;
+template <>
+inline ALPNSupport *
+NetVConnection::get_service() const
+{
+  return static_cast<ALPNSupport *>(this->_get_service(NetVConnection::Service::TLS_ALPN));
+}
+template <>
+inline void
+NetVConnection::_set_service(ALPNSupport *instance)
+{
+  this->_set_service(NetVConnection::Service::TLS_ALPN, instance);
+}
+
+class TLSBasicSupport;
+template <>
+inline TLSBasicSupport *
+NetVConnection::get_service() const
+{
+  return static_cast<TLSBasicSupport *>(this->_get_service(NetVConnection::Service::TLS_Basic));
+}
+template <>
+inline void
+NetVConnection::_set_service(TLSBasicSupport *instance)
+{
+  this->_set_service(NetVConnection::Service::TLS_Basic, instance);
+}
+
+class TLSEarlyDataSupport;
+template <>
+inline TLSEarlyDataSupport *
+NetVConnection::get_service() const
+{
+  return static_cast<TLSEarlyDataSupport *>(this->_get_service(NetVConnection::Service::TLS_EarlyData));
+}
+template <>
+inline void
+NetVConnection::_set_service(TLSEarlyDataSupport *instance)
+{
+  this->_set_service(NetVConnection::Service::TLS_EarlyData, instance);
+}
+
+class TLSCertSwitchSupport;
+template <>
+inline TLSCertSwitchSupport *
+NetVConnection::get_service() const
+{
+  return static_cast<TLSCertSwitchSupport *>(this->_get_service(NetVConnection::Service::TLS_CertSwitch));
+}
+template <>
+inline void
+NetVConnection::_set_service(TLSCertSwitchSupport *instance)
+{
+  this->_set_service(NetVConnection::Service::TLS_CertSwitch, instance);
+}
+
+class TLSSNISupport;
+template <>
+inline TLSSNISupport *
+NetVConnection::get_service() const
+{
+  return static_cast<TLSSNISupport *>(this->_get_service(NetVConnection::Service::TLS_SNI));
+}
+template <>
+inline void
+NetVConnection::_set_service(TLSSNISupport *instance)
+{
+  this->_set_service(NetVConnection::Service::TLS_SNI, instance);
+}
+
+class TLSSessionResumptionSupport;
+template <>
+inline TLSSessionResumptionSupport *
+NetVConnection::get_service() const
+{
+  return static_cast<TLSSessionResumptionSupport *>(this->_get_service(NetVConnection::Service::TLS_SessionResumption));
+}
+template <>
+inline void
+NetVConnection::_set_service(TLSSessionResumptionSupport *instance)
+{
+  this->_set_service(NetVConnection::Service::TLS_SessionResumption, instance);
+}
+
+class TLSTunnelSupport;
+template <>
+inline TLSTunnelSupport *
+NetVConnection::get_service() const
+{
+  return static_cast<TLSTunnelSupport *>(this->_get_service(NetVConnection::Service::TLS_Tunnel));
+}
+template <>
+inline void
+NetVConnection::_set_service(TLSTunnelSupport *instance)
+{
+  this->_set_service(NetVConnection::Service::TLS_Tunnel, instance);
+}
+
+class QUICSupport;
+template <>
+inline QUICSupport *
+NetVConnection::get_service() const
+{
+  return static_cast<QUICSupport *>(this->_get_service(NetVConnection::Service::QUIC));
+}
+template <>
+inline void
+NetVConnection::_set_service(QUICSupport *instance)
+{
+  this->_set_service(NetVConnection::Service::QUIC, instance);
+}
diff --git a/include/iocore/net/PollCont.h b/include/iocore/net/PollCont.h
new file mode 100644
index 0000000000..93bd0cccaa
--- /dev/null
+++ b/include/iocore/net/PollCont.h
@@ -0,0 +1,43 @@
+/** @file
+
+  A brief file description
+
+  @section license License
+
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ */
+
+#pragma once
+
+#include "Continuation.h"
+#include "Net.h"
+
+class NetHandler;
+struct PollDescriptor;
+
+struct PollCont : public Continuation {
+  NetHandler *net_handler;
+  PollDescriptor *pollDescriptor;
+  PollDescriptor *nextPollDescriptor;
+  int poll_timeout;
+
+  PollCont(Ptr<ProxyMutex> &m, int pt = EThread::default_wait_interval_ms);
+  PollCont(Ptr<ProxyMutex> &m, NetHandler *nh, int pt = EThread::default_wait_interval_ms);
... 221758 lines suppressed ...