In this lesson, you will learn how the Linux kernel orchestrates the transit of data from the physical network interface to your userspace applications using the sk_buff (socket buffer) structure.
The Lifecycle of an SKB
When a packet arrives at your network interface card (NIC), the journey begins with an interrupt. The NIC places the packet data into a ring buffer in memory and triggers an interrupt to notify the kernel. The kernel then uses a NAPI (New API) polling mechanism to process these packets efficiently, preventing the system from being overwhelmed by interrupts during high traffic.
The fundamental structure throughout this entire flow is the sk_buff (or skb). Think of the skb as a metadata-rich envelope; it doesn't just hold the packet payload, but also tracks the current position of the data within the protocol headers as it climbs the stack.
From Driver to Socket
- Device Driver: The driver allocates an
skband copies the raw frame from the NIC into theskb->databuffer. - Netif_receive_skb: The driver passes the
skbto the kernel’s generic networking layer. Here, the kernel checks for registered protocol handlers (like IP or ARP). - Protocol Layers: The
skbtravels through the protocol stack. As it moves from the Ethernet layer (Layer 2) to the IP layer (Layer 3) and finally to the TCP/UDP layer (Layer 4), the kernel "peels" off headers. It updates theskbpointers (skb->transport_header,skb->network_header) so that each layer knows exactly where its specific data begins. - Socket Receive Queue: Once the transport layer identifies the destination port, it queues the
skbonto the specific socket's receive buffer. - Userspace Copy: Finally, when your application calls
recv()orread(), the kernel performs a context switch, copying the data from theskbbuffer in kernel space into your application's user-space buffer.
/* Simplified view of SKB traversal */
struct sk_buff {
unsigned char *head;
unsigned char *data; /* Points to current header */
unsigned char *tail;
unsigned char *end;
/* ... metadata like protocol type, interface index, etc. */
};
By keeping the packet data in a single buffer and simply updating pointers as it moves through the stack, the kernel avoids expensive memory copies, ensuring high-performance packet processing.
Key Takeaway: The skb acts as the universal container for packet data, allowing the kernel to efficiently track protocol headers and move data from the wire to the application without redundant memory operations.