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.