Skip to content

Commit b62d0f3

Browse files
committed
net: sharded PCB hash table, kill TCP_DEMUX (Phase 6b)
Replace the single-lock PcbTable + shadow TcpDemuxTable with a unified sharded design: 16 independently-locked TcpShard instances for established connections (SYN_SENT, SYN_RECV, DATA, TIME_WAIT) plus a separate ListenerTable for LISTEN sockets. Architecture: - TCP_SHARDS: [IrqMutex<TcpShard>; 16], each with 8 PCB + 8 buffer slots - TCP_LISTENERS: IrqMutex<ListenerTable> with 16 slots, linear scan - FNV-1a hash on the full 4-tuple selects the shard; O(8) scan within - ConnId encodes (shard, slot) or (listener, slot) in a u32 - All locks at LOCK_LEVEL_RESOURCE; never hold two simultaneously - input() locks one shard for established, falls back to listener table for SYNs, then locks the child's shard to install — three sequential lock acquisitions, never nested Deleted: TcpDemuxTable, TcpDemuxBucket, TcpEstablishedEntry, TcpListenerEntry, TCP_DEMUX, TCP_DEMUX_BUCKETS_TABLE, tcp_demux_hash, and all register/unregister/lookup calls in socket.rs and ipv4.rs (~300 lines removed from listener.rs, ~35 from ipv4.rs, ~25 from socket.rs). The sharded table is the single source of truth. Zero unsafe blocks throughout.
1 parent aa5de6a commit b62d0f3

10 files changed

Lines changed: 805 additions & 1089 deletions

File tree

net/src/ipv4.rs

Lines changed: 0 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -208,40 +208,6 @@ fn dispatch_tcp(src_ip: [u8; 4], dst_ip: [u8; 4], pkt: &PacketBuf, checksum_rx:
208208
let payload = &ip_payload[hdr_len..];
209209
let now_ms = slopos_utils::clock::uptime_ms();
210210

211-
// Demux table pre-lookup for debug/fast-path validation.
212-
// The demux table provides O(n) lookup by 4-tuple (established) or
213-
// 2-tuple (listener). The actual state machine processing still goes
214-
// through tcp_input() which uses TcpConnectionTable internally.
215-
{
216-
use super::tcp::listener::TCP_DEMUX;
217-
use super::types::{Ipv4Addr, Port};
218-
219-
let demux = TCP_DEMUX.lock();
220-
let local_ip = Ipv4Addr(dst_ip);
221-
let local_port = Port(hdr.dst_port);
222-
let remote_ip = Ipv4Addr(src_ip);
223-
let remote_port = Port(hdr.src_port);
224-
225-
if let Some(conn_id) =
226-
demux.lookup_established(local_ip, local_port, remote_ip, remote_port)
227-
{
228-
klog_debug!(
229-
"tcp demux: established conn_id={} for {}:{} -> {}:{}",
230-
conn_id,
231-
src_ip[0],
232-
src_ip[1],
233-
hdr.src_port,
234-
hdr.dst_port
235-
);
236-
} else if let Some(sock_idx) = demux.lookup_listener(local_ip, local_port) {
237-
klog_debug!(
238-
"tcp demux: listener sock_idx={} for port {}",
239-
sock_idx,
240-
hdr.dst_port
241-
);
242-
}
243-
}
244-
245211
let actions = tcp::input(src_ip, dst_ip, &hdr, options, payload, now_ms);
246212

247213
for seg in actions.segments() {

net/src/socket.rs

Lines changed: 11 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -894,25 +894,14 @@ pub fn socket_notify_tcp_activity(actions: &tcp::Actions) {
894894
if let Some(conn_id) = actions.conn_id {
895895
socket_notify_tcp_idx_waiters(conn_id);
896896

897-
// When a connection transitions to Established, register it
898-
// in the TCP demux table for fast 4-tuple lookup.
897+
// Wire completed 3WHS into the listener's accept queue.
898+
// The child PCB inherits the parent listener's socket_id at
899+
// install time, so we read it directly instead of looking up
900+
// the old TCP_DEMUX table.
899901
if actions.notify.contains(tcp::SocketNotify::NEW_ESTABLISHED) {
900-
if let Some(tuple) = tcp::with_pcb(conn_id, |pcb| pcb.tuple) {
901-
let _ = tcp_listener::TCP_DEMUX.lock().register_established(
902-
Ipv4Addr(tuple.local_ip),
903-
Port(tuple.local_port),
904-
Ipv4Addr(tuple.remote_ip),
905-
Port(tuple.remote_port),
906-
conn_id.0,
907-
);
908-
909-
// Wire completed 3WHS into the listener's accept queue.
910-
// Read the PCB metadata to build the AcceptedConn — this
911-
// is the ACK leg, not the SYN leg, so actions.accepted is
912-
// not populated.
913-
let listener_sock_idx = tcp_listener::TCP_DEMUX
914-
.lock()
915-
.lookup_listener(Ipv4Addr(tuple.local_ip), Port(tuple.local_port));
902+
if let Some(_tuple) = tcp::with_pcb(conn_id, |pcb| pcb.tuple) {
903+
let listener_sock_idx =
904+
tcp::with_pcb(conn_id, |pcb| pcb.socket_id.map(|s| s.0)).flatten();
916905
if let Some(listener_idx) = listener_sock_idx {
917906
let accepted_meta = tcp::with_pcb(conn_id, |pcb| {
918907
let tcp::PcbState::Data(d) = &pcb.state else {
@@ -1409,12 +1398,8 @@ pub fn socket_listen(sock_idx: u32, backlog: u32) -> i32 {
14091398
}
14101399
sock.state = SocketState::Listening;
14111400

1412-
// Register listener in TCP demux table.
1413-
let _ = tcp_listener::TCP_DEMUX
1414-
.lock()
1415-
.register_listener(local.ip, local.port, sock_idx);
1416-
14171401
// Set bidirectional link on the connection.
1402+
// (Listener is already registered in TCP_LISTENERS by tcp::listen.)
14181403
tcp::set_socket_idx(tcp_idx, Some(tcp::SocketId(sock_idx)));
14191404

14201405
0
@@ -2126,7 +2111,7 @@ pub fn socket_recv(sock_idx: u32, buf: *mut u8, len: usize) -> i64 {
21262111
}
21272112

21282113
pub fn socket_close(sock_idx: u32) -> i32 {
2129-
let (tcp_idx, udp_unbind, icmp_unbind, recv_hint, send_hint, accept_hint, was_listener) = {
2114+
let (tcp_idx, udp_unbind, icmp_unbind, recv_hint, send_hint, accept_hint, _was_listener) = {
21302115
let mut table = NEW_SOCKET_TABLE.lock();
21312116
let Some(sock) = table.get_mut(sock_idx as usize) else {
21322117
return errno_i32(ERRNO_ENOTSOCK);
@@ -2173,15 +2158,9 @@ pub fn socket_close(sock_idx: u32) -> i32 {
21732158
)
21742159
};
21752160

2176-
// Unregister from TCP demux table.
2177-
if was_listener {
2178-
tcp_listener::TCP_DEMUX.lock().unregister_listener(sock_idx);
2179-
}
2161+
// Release the TCP connection (if any). The sharded table handles
2162+
// cleanup internally via release(); no separate demux unregister needed.
21802163
if let Some(tcp_idx) = tcp_idx {
2181-
tcp_listener::TCP_DEMUX
2182-
.lock()
2183-
.unregister_established(tcp_idx.0);
2184-
// Clear the bidirectional link.
21852164
tcp::set_socket_idx(tcp_idx, None);
21862165
}
21872166

net/src/tcp/actions.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -148,8 +148,8 @@ bitflags! {
148148
/// can return 0 from `recv()` once buffered data is drained.
149149
const PEER_CLOSED = 1 << 4;
150150
/// The connection just completed its 3-way handshake. Signals
151-
/// the glue layer to register the child in `tcp::listener::TCP_DEMUX`
152-
/// for fast 4-tuple lookup on subsequent segments.
151+
/// the glue layer to allocate a buffer and wire the child into
152+
/// the listener's accept queue.
153153
const NEW_ESTABLISHED = 1 << 5;
154154
}
155155
}

0 commit comments

Comments
 (0)