Build a TCP/IP Stack from Scratch · Module 01

How Virtual Networking Works in Docker

Concept: How virtual networking works in Docker

Before we start typing commands, let's take a moment to understand what's actually happening behind the curtain when two Docker containers "talk" to each other.

The Virtual LAN

When you run containers, Docker quietly sets up a tiny virtual network inside your computer. Think of it as a private little LAN that exists only on your machine. Each container plugged into that network gets its own virtual Ethernet interface and IP address, just like real computers connected to a home router.

Here's the mental picture:

 ┌──────────────────────────────────┐
 │ Docker bridge │
 │ (like a virtual switch) │
 └──────────────────────────────────┘
 ↑ ↑
 client: eth0 (10.10.0.3) stack: eth0 (10.10.0.4)

The Docker Bridge

The Docker bridge behaves just like a physical Ethernet switch. It forwards packets between containers that are connected to the same network. So when the client container "pings" the stack container, that packet doesn't go out to the Internet — it just travels through this internal bridge.

TAP Interface (Coming Soon)

Now, in a few modules, we'll introduce something special inside the stack container: a TAP interface. This will give your own C program a "wire" to read and write raw Ethernet frames — effectively replacing the kernel's networking logic. But we're not there yet. First, we need to make sure ordinary network traffic between containers works exactly as expected.

The Packet Journey

So, when you see commands like:

docker compose exec client ping 10.10.0.4

what's really happening is this:

  1. The client container uses its built-in Linux TCP/IP stack to send an ICMP Echo Request to 10.10.0.4.
  2. The packet goes out its virtual interface, enters the Docker bridge, and pops out at the stack container's interface.
  3. The stack container's kernel receives it, sends back an Echo Reply, and the bridge delivers it back to the client.

That's it — a complete round trip, fully virtualized, no cables involved.

Once this basic communication works, we'll slowly take over those responsibilities — replacing the kernel's automatic replies with our own code. But for now, we just need this bridge and these two containers alive and chatting.

What's really happening is this:

  1. The client container uses its built-in Linux TCP/IP stack to send an ICMP Echo Request to 10.10.0.4
  2. The packet goes out its virtual interface, enters the Docker bridge, and pops out at the stack container's interface
  3. The stack container's kernel receives it, sends back an Echo Reply, and the bridge delivers it back to the client

That's it — a complete round trip, fully virtualized, no cables involved.

Info: Once this basic communication works, we'll slowly take over those responsibilities — replacing the kernel's automatic replies with our own code.