Virtual Ethernet (veth): The Cable Inside Linux
A network namespace is like a computer with no network cable plugged in. A virtual Ethernet (veth) pair is that cable. It is the simplest and most important building block of Linux virtual networking, forming the foundation of Docker, Kubernetes, Podman, LXC, and many other technologies.
Learning Objectives
By the end of this chapter, you will be able to:
- Understand what a virtual Ethernet (veth) pair is
- Explain how packets travel through a veth pair
- Create and inspect veth interfaces
- Connect two network namespaces using a veth pair
- Assign IP addresses and exchange packets
- Observe packet counters and interface states
- Troubleshoot common veth issues
The Problem
In the previous chapter, we created network namespaces.
Host
Namespace A
lo
Host
Namespace B
lo
- Each namespace had its own network stack.
- Each namespace had its own routing table.
- Each namespace had its own sockets.
But there was one major problem.
They couldn't communicate with anything.
They were like two computers sitting on a desk with no Ethernet cables.
What Is a veth Pair?
A virtual Ethernet pair consists of two virtual network interfaces permanently connected together.
Think of it as an Ethernet cable with exactly two ends.
+---------+======================+---------+
| vethA | | vethB |
+---------+======================+---------+
Anything transmitted into one end immediately appears at the other end.
Unlike a physical Ethernet cable:
- there is no switch
- there is no hub
- there is no routing
- there is no packet modification
The Linux kernel simply copies frames from one interface to its peer.
Understanding the "Pair"
A veth interface can never exist by itself.
Creating one interface automatically creates its peer.
vethA <-----------------> vethB
Delete one interface:
ip link delete vethA
Both interfaces disappear.
The pair is treated as one logical object by the kernel.
How Packets Flow
Suppose a process sends an ICMP Echo Request.
Namespace A
Application
│
▼
TCP/IP Stack
│
▼
vethA
│
====================
Virtual Cable
====================
│
vethB
│
▼
TCP/IP Stack
│
Application
Namespace B
The packet never leaves the Linux kernel.
No physical NIC is involved.
No switch is involved.
No external network is involved.
Everything happens entirely in memory.
This makes veth communication extremely fast.
Creating a veth Pair
Create a pair:
sudo ip link add vethA type veth peer name vethB
Verify:
ip link show
Example:
...
10: vethA@if11: <BROADCAST,MULTICAST>
11: vethB@if10: <BROADCAST,MULTICAST>
...
Notice the peer notation:
vethA@if11
vethB@if10
Each interface knows the index of its peer.
Inspecting the Interfaces
Display detailed information:
ip -d link show vethA
Example:
vethA@if11
link/ether 8a:5d:7d:...
veth
Notice the interface type:
veth
Unlike eth0, which is driven by a hardware device driver, these interfaces exist entirely in software.
Bringing the Interfaces Up
Initially the interfaces are down.
Check:
ip link show vethA
Bring them up:
sudo ip link set vethA up
sudo ip link set vethB up
Verify:
ip link show vethA
Example:
UP,LOWER_UP
Unlike physical interfaces, LOWER_UP simply means the peer is present and operational.
Assigning IP Addresses
Assign addresses:
sudo ip addr add 10.10.10.1/24 dev vethA
sudo ip addr add 10.10.10.2/24 dev vethB
Verify:
ip addr show vethA
Example:
inet 10.10.10.1/24
Testing Connectivity
Ping the peer:
ping 10.10.10.2
Output:
64 bytes from 10.10.10.2
The packet never touched a physical network.
It traveled only through the kernel.
Watching Packet Counters
Display statistics:
ip -s link show vethA
Example:
RX:
packets 120
TX:
packets 120
Run another ping.
Display the counters again.
The numbers increase immediately.
Packet counters are one of the easiest ways to verify traffic is flowing.
Connecting Network Namespaces
Now we'll connect two isolated namespaces.
Create them:
sudo ip netns add blue
sudo ip netns add red
Enable loopback:
sudo ip netns exec blue ip link set lo up
sudo ip netns exec red ip link set lo up
Create the veth Pair
sudo ip link add blue-veth type veth peer name red-veth
Current layout:
Host
blue-veth <-------> red-veth
Both interfaces still belong to the host namespace.
Move Each Interface
Move one interface into each namespace.
sudo ip link set blue-veth netns blue
sudo ip link set red-veth netns red
Now the topology becomes:
Namespace blue
blue-veth
||
====================
Virtual Ethernet
====================
||
red-veth
Namespace red
This is one of the most common operations performed by container runtimes.
Configure the Interfaces
Inside blue:
sudo ip netns exec blue ip addr add 10.0.0.1/24 dev blue-veth
sudo ip netns exec blue ip link set blue-veth up
Inside red:
sudo ip netns exec red ip addr add 10.0.0.2/24 dev red-veth
sudo ip netns exec red ip link set red-veth up
Verify:
sudo ip netns exec blue ip addr
Example:
lo
blue-veth
Test the Connection
From blue:
sudo ip netns exec blue ping 10.0.0.2
Output:
64 bytes from 10.0.0.2
Reverse direction:
sudo ip netns exec red ping 10.0.0.1
Communication works.
You have connected two isolated Linux systems using nothing but kernel networking primitives.
Observe the Neighbor Table
Before pinging:
sudo ip netns exec blue ip neigh
Output:
<no output>
Generate traffic:
sudo ip netns exec blue ping -c 1 10.0.0.2
Check again:
sudo ip netns exec blue ip neigh
Example:
10.0.0.2 dev blue-veth lladdr 5a:18:df:3b:17:91 REACHABLE
Even though everything is virtual, ARP still works exactly as it does on a physical Ethernet network.
This is an important observation.
The Linux networking stack does not distinguish between physical and virtual Ethernet devices when performing Layer 2 communication.
Observe Packet Counters
Inside the namespace:
sudo ip netns exec blue ip -s link show blue-veth
Generate more traffic:
sudo ip netns exec blue ping -c 5 10.0.0.2
Check again:
sudo ip netns exec blue ip -s link show blue-veth
Both RX and TX counters increase.
Packet accounting works exactly as it does on physical interfaces.
Capturing Traffic
Because a veth interface behaves like a normal Ethernet interface, tools such as tcpdump work without modification.
Capture packets:
sudo ip netns exec blue tcpdump -i blue-veth
From another terminal:
sudo ip netns exec red ping 10.0.0.1
You will observe:
- ARP requests
- ARP replies
- ICMP Echo Requests
- ICMP Echo Replies
From tcpdump's perspective, this is just another Ethernet interface.
The Peer Relationship
The peer relationship is visible through ip link.
Example:
blue-veth@if8
The @if8 indicates the interface index of its peer.
Likewise:
red-veth@if7
This makes it easy to identify connected interfaces while troubleshooting.
What Happens If One Side Goes Down?
Bring one interface down:
sudo ip netns exec red ip link set red-veth down
Now inspect the other side:
sudo ip netns exec blue ip link show blue-veth
You'll notice that carrier state changes.
Attempting to ping now fails because the virtual cable is effectively unplugged.
This behavior closely matches a physical Ethernet cable.
Cleaning Up
Delete the namespaces:
sudo ip netns delete blue
sudo ip netns delete red
Notice that the veth interfaces disappear automatically.
Why?
Because they belonged to the namespaces that were deleted.
No manual cleanup is required.
Where veth Is Used
The veth driver is one of the most widely used networking components in Linux.
Examples include:
- Docker
- Podman
- Kubernetes
- containerd
- CRI-O
- LXC/LXD
- CNI plugins
Whenever a container receives an eth0 interface, one end of a veth pair is typically inside the container's network namespace, while the other end remains in the host namespace or is attached to a software switch.
Common Mistakes
Forgetting to Bring Interfaces Up
Creating a veth pair does not automatically enable it.
Always execute:
ip link set <interface> up
Forgetting Loopback
A namespace usually needs its loopback interface enabled.
ip netns exec <namespace> ip link set lo up
Moving the Wrong Interface
Once an interface is moved into another namespace, it disappears from the host's interface list.
To inspect or configure it afterward, use:
ip netns exec <namespace> ...
Assuming veth Performs Routing
A veth pair is only a Layer 2 point-to-point link.
It does not:
- route packets
- switch frames
- perform NAT
- filter traffic
Those responsibilities belong to other Linux networking components.
Key Takeaways
- A veth pair is a pair of virtual Ethernet interfaces permanently connected inside the Linux kernel.
- Packets transmitted on one interface immediately appear on its peer without leaving the host.
- Veth interfaces behave like normal Ethernet interfaces and fully participate in ARP, IP, ICMP, and other networking protocols.
- One end of a veth pair is commonly placed inside a network namespace while the other remains in the host namespace or connects to a software switch.
- Container runtimes such as Docker, Podman, Kubernetes, and LXC use veth pairs to connect isolated network namespaces.
- A veth pair provides only a direct Layer 2 connection; it does not perform switching, routing, or firewalling.
Coming Next
A veth pair connects exactly two endpoints. But what if you need to connect ten containers, twenty virtual machines, or hundreds of workloads to the same Layer 2 network?
In the next chapter, we'll introduce the Linux bridge, a software implementation of an Ethernet switch. You'll learn how Linux forwards Ethernet frames between multiple interfaces, builds MAC address tables, and forms the virtual networks used by containers and virtualization platforms.