1. Veth Pairs (Virtual Ethernet Interfaces) #
A veth pair acts as a virtual bidirectional Ethernet cable. Packets transmitted on one end.
graph LR
subgraph Host ["Linux Host"]
direction LR
subgraph Veth0_Dev ["veth0 Interface"]
A["veth0
192.168.1.1/24"]
end
subgraph Veth1_Dev ["veth1 Interface"]
B["veth1
192.168.1.2/24"]
end
A <===> |"Virtual Ethernet Cable (Peer)"| B
end
Basic Commands #
# Create a veth pair named veth0 and veth1
ip link add veth0 type veth peer name veth1
# Assign an IP address to veth0
ip addr add 192.168.1.1/24 dev veth0
# Bring the interfaces up
ip link set veth0 up
ip link set veth1 up
# Verify created devices
ip link showCrucial Kernel Parameters #
When testing local veth packet routing on the same host, the kernel’s Reverse Path Filtering (rp_filter) or local interface route checks may silently drop packets.
-
sysctl -w net.ipv4.conf.veth0.rp_filter=0: Disables strict reverse path filtering (RPF) checks.
-
sysctl -w net.ipv4.conf.veth0.accept_local=1: Allows accepting packets with a local source IP.
Inspecting Traffic #
# Capture packets passing through the virtual interface
tcpdump -nn -i veth0Veth Kernel Internals & Packet Path #
Unlike physical network cards that use DMA to push frames to hardware, veth relies on veth_xmit() inside the driver:
- Application calls send() –> allocates an sk_buff payload.
- veth_xmit() grabs the peer device handle (priv->peer).
- Switches the packet context to the peer interface via netif_rx() or netif_receive_skb().
- Triggering a softirq (NET_RX_SOFTIRQ) processes the frame as an incoming packet on the peer device.
2. Network Namespaces (netns) #
Network namespaces isolate network stacks across processes—providing independent routing tables, firewall rules (iptables/nftables), socket lists, ARP tables, and network interfaces (lo, eth0).
Working with Network Namespaces #
# Create a network namespace named net1
ip netns add net1
# Create a veth pair
ip link add veth-host type veth peer name veth-net1
# Move veth-net1 inside the net1 namespace
ip link set veth-net1 netns net1
# Configure IP inside net1
ip netns exec net1 ip addr add 192.168.1.2/24 dev veth-net1
ip netns exec net1 ip link set veth-net1 up
ip netns exec net1 ip link set lo upKernel Representations #
- Process to Namespace (task_struct –> nsproxy –> net): A process references its namespace via current->nsproxy->net_ns.
- The struct net Structure: Contains loopback pointers (loopback_dev), IPv4 protocols (netns_ipv4), sysctl knobs, and active socket tracking tables.
Lifecycle & Creation #
- clone() Flag: Passing CLONE_NEWNET to clone() or unshare() provisions a new struct net instance.
- Subsystem Initialization: Each network subsystem (TCP, UDP, Netfilter, Routing) executes its init_net constructor function inside the new namespace.
- Sockets and Namespaces: Every socket (struct sock) stores a pointer sk_net referencing its parent struct net. Sockets cannot cross namespace boundaries once bound.
3. Linux Bridge (net_bridge) #
A Linux Bridge operates as a virtual Layer-2 Software Switch, connecting multiple veth endpoints or physical interfaces into a shared broadcast domain.
Primary Kernel Structures #
-
struct net_device: Represents the virtual bridge interface (br0).
-
struct net_bridge: Represents the internal bridge state, including port lists, MAC forwarding tables (fdb), and spanning tree parameters.
Packet Traversal in a Bridge #
- An incoming frame arrives at a bridged port via netif_receive_skb().
- Execution diverts to br_handle_frame().
- The bridge checks its MAC forwarding table (FDB):
- Unicast Hit: Forwards directly to the target port (br_forward()).
- Unicast Miss / Broadcast / Multicast: Floods the frame out to all connected ports (br_flood()).
4. Routing, NAT, and External Connectivity #
To forward container traffic to an external network (or route host traffic to a container), Linux uses Routing Tables and Netfilter NAT.
Route Tables #
Linux uses multiple route tables evaluated by policy routing rules (ip rule):
-
local: Reserved for local IP addresses and loopback traffic.
-
main: Default table for standard route entries.
Enable kernel IP forwarding: #
sysctl -w net.ipv4.ip_forward=1Netfilter Architecture & Hooks #
Table PrioritiesEvaluated in order: raw –> mangle –> nat –> filter.
flowchart TD
Prerouting["PREROUTING
(DNAT / Port Forwarding)"]
Route1{"Routing Decision"}
Input["INPUT
(Local Filter)"]
Process["Local Process"]
Output["OUTPUT
(Outbound Filter)"]
Forward["FORWARD
(Packet Routing)"]
Route2{"Routing Decision"}
Postrouting["POSTROUTING
(SNAT / Masquerade)"]
%% Flow Path
Prerouting --> Route1
%% Local Inbound & Outbound
Route1 -- Local IP --> Input --> Process --> Output --> Route2 --> Postrouting
%% Forwarding Path
Route1 -- Other IP --> Forward --> Postrouting
Port Forwarding (Docker -p 80:80 equivalent) #
- Source NAT (SNAT / MASQUERADE): Rewrites private container IPs to host IPs for outbound internet access.
iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -j MASQUERADE- Destination NAT (DNAT): Redirects inbound traffic on host port 80 to container port 80.
iptables -t nat -A PREROUTING -p tcp --dport 80 -j DNAT --to-destination 192.168.1.2:80