Tcp Ingress Flow
John Dykstra's Blog

- Ingress packets are delivered to TCP, in softIRQ context, through tcp_v4_rcv().
- If the sock is currently owned by a task, we can't touch most of its contents, so the packet is stashed on the backlog queue.
- If the sock is not owned, but there is a task blocked in tcp_recvmsg() on this socket, the packet goes into the prequeue and the task is unblocked.
- Otherwise, we call tcp_v4_do_rcv() immediately, and the data contents of the packet are going to end up in the receive queue.
- The backlog queue is emptied in user context when the task that had locked the sock gets around to releasing it. The packets go to tcp_v4_do_rcv() and thence to the receive queue.
- Once the task in tcp_recvmsg() wakes up, it calls tcp_prequeue_process(), which pulls each packet in turn off the prequeue and passes it to tcp_v4_do_recv(). That function recognizes it is in the context of the receiving task, and moves the data contents of the packet directly to the application's buffer.
- Data that makes it into the receive queue gets pulled off by tcp_recvmsg() and written into the application buffer. Note that this code must preserve packet ordering--the receive queue must be empty before packets are pulled off the prequeue.
- Also note that packets in the backlog and prequeues have not yet been seen by the TCP state machine in tcp_v4_do_rcv(), so for the length of time they sit there, they are unacknowledged. This latency gets wrapped up in the bandwidth-delay product for big transfers, but it can be an issue for short connections stuck in slow-start.