Operations 13 min read

How Linux Receives and Sends Network Packets: A Step‑by‑Step Deep Dive

This article walks through the complete Linux network packet lifecycle—from NIC interrupt handling and DMA transfer, through kernel soft‑irq processing, netfilter hooks, and protocol‑stack handling, to the reverse path for sending UDP packets, illustrating each function and queue involved.

Liangxu Linux
Liangxu Linux
Liangxu Linux
How Linux Receives and Sends Network Packets: A Step‑by‑Step Deep Dive

Packet Reception Overview

When a network interface card (NIC) receives a packet, its driver—loaded during kernel boot—handles the interrupt and transfers the data via DMA into a memory buffer allocated by the driver. The NIC then raises a hardware IRQ, prompting the CPU to invoke the registered interrupt handler, which disables further NIC interrupts, starts a soft‑irq, and hands the packet to the kernel networking stack.

Kernel Soft‑IRQ Processing

The ksoftirqd process calls net_rx_action. net_rx_action invokes the driver’s poll function to retrieve packets.

The driver wraps the raw data into an skb (socket buffer) and calls napi_gro_receive. napi_gro_receive performs Generic Receive Offload (GRO) and, if Receive Packet Steering (RPS) is enabled, enqueues the packet via enqueue_to_backlog into input_pkt_queue.

If the backlog is full, the packet is dropped; its size is controlled by net.core.netdev_max_backlog.

The kernel then processes the queue with __netif_receive_skb_core, delivering the packet to the appropriate netfilter hook ( NF_INET_PRE_ROUTING) and eventually to the transport layer.

For raw sockets (e.g., tcpdump), the packet is copied to the socket’s receive queue.

Finally, the packet reaches the TCP/IP stack for further handling.

IP Layer Processing

ip_rcv

validates the packet and invokes the NF_INET_PRE_ROUTING netfilter chain.

Routing decisions are made; if the destination is local, ip_local_deliver is called, otherwise ip_forward handles forwarding.

Both paths pass through additional netfilter hooks ( NF_INET_LOCAL_IN, NF_INET_FORWARD) before reaching the transport layer.

Transport Layer (UDP) Reception

udp_rcv

looks up the destination socket via __udp4_lib_lookup_skb.

If a matching socket exists, sock_queue_rcv_skb checks the receive queue, applies any BPF filter via sk_filter, and enqueues the packet with __skb_queue_tail, then notifies the application with sk_data_ready.

Packet Transmission Overview

The sending path mirrors the reception flow but in reverse, starting from the application layer.

Application Layer

Applications create a socket with socket(...) and send data via sendto(...), which calls inet_sendmsg. inet_sendmsg ensures a source port is bound (using inet_autobind and get_port) before handing the packet to the UDP layer.

UDP Transmission

udp_sendmsg

obtains routing info via ip_route_output_flow, builds an skb with ip_make_skb, and fills UDP headers.

The packet is passed to the IP layer.

IP Transmission

ip_send_skb

initiates sending; __ip_local_out_sk sets length and checksum, then traverses the NF_INET_LOCAL_OUT netfilter hook. dst_output_sk calls ip_output, which processes NF_INET_POST_ROUTING (e.g., SNAT) and then ip_finish_output.

Routing lookup determines the next‑hop MAC address; ARP resolution occurs via __ipv4_neigh_lookup_noref or __neigh_create.

The packet is handed to dst_neigh_output, which invokes neigh_resolve_output to fill the MAC address and finally calls dev_queue_xmit.

Device Queue and Transmission

dev_queue_xmit

selects a queue discipline (qdisc); if none, it directly calls dev_hard_start_xmit. dev_hard_start_xmit may clone the skb for packet sniffers (e.g., tcpdump) and then calls the driver’s ndo_start_xmit to push the packet onto the NIC’s transmit queue.

If transmission fails, the kernel schedules a NET_TX_SOFTIRQ via net_tx_action for retry.

After the NIC finishes sending, it generates an interrupt to notify the CPU, which cleans up the skb and completes the transmission cycle.

Key Takeaways

Both reception and transmission heavily rely on soft‑irqs to offload work from hardware interrupt context.

Netfilter hooks ( NF_INET_*) provide extensibility points for firewall, NAT, and other packet‑processing modules.

Backlog queues and configurable limits ( net.core.netdev_max_backlog) prevent packet loss under high load.

Understanding the sequence of kernel functions— net_rx_action, poll, napi_gro_receive, udp_rcv, ip_send_skb, dev_queue_xmit, etc.—is essential for debugging networking issues or developing custom kernel modules.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

UDPdevice driver
Liangxu Linux
Written by

Liangxu Linux

Liangxu, a self‑taught IT professional now working as a Linux development engineer at a Fortune 500 multinational, shares extensive Linux knowledge—fundamentals, applications, tools, plus Git, databases, Raspberry Pi, etc. (Reply “Linux” to receive essential resources.)

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.