Linux bridge — switch L2 ảo (docker0)
Bridge là switch L2 trong kernel: tạo bridge, gắn veth, quan sát MAC learning (FDB), và vì sao docker0 chính là bridge — nền Docker bridge network.
TL;DR: Linux bridge là switch L2 ảo trong kernel: nhiều netdev (veth, tap, eth) gắn làm port, frame được forward theo MAC — không “route” IP giữa port. Tạo bằng ip link add … type bridge, gắn port bằng ip link set <dev> master <br>, học MAC vào FDB (Forwarding Database). docker0 chính là bridge mặc định của Docker: mỗi container một veth, đầu host là port trên docker0. Pitfall hay gặp: bridge thiếu IP (container mất gateway), port/ip_forward off, hoặc quên up cả veth lẫn bridge.
Staging: hai container cùng bridge network, ping chéo timeout. Junior đã kiểm tra IP trong netns — đúng subnet 172.17.0.0/16. Bạn hỏi: “đầu host của veth đã master docker0 và UP chưa? FDB có MAC peer chưa?” Một đầu veth còn dangling (không master), bridge không học được đường L2. ip link set … master docker0 + up → ARP/ping sống. Không phải DNS, không phải app — cổng switch ảo chưa cắm.
Bài 02 — Virtual network devices đã cho cáp (veth). Bài này cho switch gắn nhiều cáp thành một LAN ảo — đúng mảnh Docker gọi “bridge network”. Stack softirq/sk_buff bài 01 vẫn chạy; bridge thêm bước L2 forward giữa port trước khi gói lên IP/local hay ra netfilter FORWARD (bài 04).
Bài này implement bridge + veth và quan sát MAC learning, fade: lab gắn port 1 đủ bước → bạn tự gắn port 2 trước khi xem lời giải.
1. Analogy — Switch rack, bảng MAC, và cổng docker0
Hình dung một switch Ethernet trong rack lab:
- Nhiều cổng (port) — cắm cáp từ máy A, máy B, máy C.
- Switch học MAC: “máy A gắn cổng 3” sau khi thấy frame từ A vào cổng 3.
- Frame tới MAC đã học → chỉ ra đúng cổng; broadcast/unknown → flood các cổng còn lại (trừ cổng vào).
- Switch không “route” theo IP giữa các cổng cùng VLAN/LAN — nó sống ở L2.
| Đời thường (switch rack) | Linux bridge |
|---|---|
| Chassis switch | Netdev loại bridge (br0, docker0) |
| Cổng RJ45 | Port = netdev slave (master br0) — thường veth host-side |
| Bảng MAC (CAM) | FDB — Forwarding Database |
| Học MAC khi thấy traffic | Dynamic FDB entry sau frame/ARP |
| Cáp máy ↔ switch | veth pair: peer trong netns/container, đầu kia port trên bridge |
Bridge = switch ảo. veth = cáp. docker0 = switch mặc định Docker cắm các cáp container. Debug container-to-container: hỏi cùng bridge? port UP? FDB có MAC? trước khi nhảy iptables.
2. Bridge là gì — vì sao gọi là switch L2?
Linux bridge (kernel bridge module / netdev type bridge) gom nhiều interface thành một miền broadcast L2. Kernel:
- Nhận Ethernet frame trên một port.
- Tra FDB theo MAC đích.
- Forward frame ra port đúng (hoặc flood nếu chưa biết / broadcast).
- Có thể đồng thời coi bridge như một netdev trên host: gán IP cho
br0/docker0để host làm gateway L3 của LAN ảo.
Bridge ≠ router (và ≠ veth)
| Bridge (L2) | Router / IP forward (L3) | veth (bài 02) | |
|---|---|---|---|
| Quyết định theo | MAC (FDB) | IP + route table | Peer cố định A↔B |
| Giữa hai “máy” | Cùng LAN/subnet logic | Khác subnet, cần gateway | Chỉ đúng một cáp |
| docker0 làm gì | Switch các container | Host IP trên bridge + ip_forward/NAT ra WAN | Cáp netns↔host |
Hai container trên cùng docker0 ping nhau chủ yếu là path L2 qua bridge (veth → bridge → veth). Container ra Internet thêm bước L3: default route tới IP trên docker0, rồi host forward + NAT — netfilter (bài 04), không phải “bridge tự route WAN”.
flowchart TB
C1["Container eth0"] -->|"veth peer"| H1["Host veth port"]
C2["Container eth0"] -->|"veth peer"| H2["Host veth port"]
H1 --> BR["bridge docker0 / br0"]
H2 --> BR
BR -->|"optional IP gateway"| HOST["Host IP stack"]
HOST -->|"forward + NAT later"| WAN["Outside"]Vì sao container cần bridge thay vì chỉ một veth pair?
Một veth pair chỉ nối hai đầu. Ba container cần “cùng LAN” → hoặc mesh nhiều pair (không scale), hoặc một switch nhiều port. Bridge = mô hình switch: N veth host-side làm N port, mỗi container một cáp.
3. Tạo bridge và gắn veth — lab fade
Chạy trên Linux (VM/WSL2/host), thường cần sudo. Lab cùng netns (đơn giản hoá): hai “đầu máy” là hai veth peer; hai đầu host-side gắn br0. (Production: peer nằm netns container — cùng cơ chế master/FDB; netns đầy đủ ở module sau.)
3.1 Worked — tạo bridge + pair 1 + gắn port 1
# 1) Create a bridge (virtual L2 switch)
sudo ip link add name br0 type bridge
sudo ip link set br0 up
# 2) Create first veth pair: host-side port + "endpoint" side
sudo ip link add veth-h1 type veth peer name veth-e1
# 3) Attach ONLY the host-side end as a bridge port (worked step)
sudo ip link set veth-h1 master br0
sudo ip link set veth-h1 up
sudo ip link set veth-e1 up
# 4) Give the endpoint an IP (host is not on this IP yet)
sudo ip addr add 10.30.0.11/24 dev veth-e1
# 5) Bridge often needs an IP if it is the gateway for the LAN
sudo ip addr add 10.30.0.1/24 dev br0
# Inspect: veth-h1 should show master br0
ip link show veth-h1
ip link show br0
Bạn đã có: switch br0, một port (veth-h1), một endpoint veth-e1 với IP 10.30.0.11. Endpoint thứ hai chưa có — chưa ping được “máy” khác trên cùng bridge.
Tự làm trước khi xem lời giải. Tạo pair thứ hai (veth-h2 / veth-e2), gắn đúng đầu host vào br0, up cả hai đầu, gán 10.30.0.12/24 cho endpoint. Sau đó ping -c 2 10.30.0.12 từ phía dùng veth-e1 (hoặc ping -I veth-e1 10.30.0.12 nếu stack yêu cầu chọn iface).
Gợi ý định hướng (không chép lệnh): mirror đúng thứ tự bước 2–4 ở trên; IP gateway trên br0 đã có — đừng gán IP lên veth-h2 (port slave thường không cần IP).
3.2 Lời giải — gắn interface 2
# Create second pair
sudo ip link add veth-h2 type veth peer name veth-e2
# Host-side -> bridge port (this is the step most people skip)
sudo ip link set veth-h2 master br0
sudo ip link set veth-h2 up
sudo ip link set veth-e2 up
# Endpoint IP on the "other machine"
sudo ip addr add 10.30.0.12/24 dev veth-e2
# L2 via bridge: e1 <-> br0 <-> e2
ping -c 2 -I veth-e1 10.30.0.12
# or: ping -c 2 10.30.0.12 if routing/src selection already prefers veth-e1
# Optional cleanup
# sudo ip link del veth-h1
# sudo ip link del veth-h2
# sudo ip link del br0
Cơ chế: frame từ veth-e1 → peer veth-h1 (port) → bridge học/flood → ra veth-h2 → peer veth-e2. Không cần route giữa .11 và .12 nếu cùng /24 và ARP resolve qua bridge. Nếu ping fail: kiểm tra cả hai host-side có master br0, cả bridge + bốn đầu veth UP, IP đúng iface.
flowchart LR
E1["veth-e1 .11"] -->|"pair"| H1["veth-h1 port"]
E2["veth-e2 .12"] -->|"pair"| H2["veth-h2 port"]
H1 --> BR0["br0"]
H2 --> BR04. FDB — bridge học MAC thế nào?
FDB (Forwarding Database) là bảng MAC → port của bridge — tương đương bảng MAC trên switch vật lý.
- Frame vào port P với MAC nguồn S → bridge học: “S nằm sau port P” (dynamic entry, có ageing timeout).
- Frame có MAC đích D:
- D đã học → forward chỉ ra port đã ghi;
- D là broadcast/multicast hoặc unknown → flood các port khác (trừ port vào).
- Sau vài ARP/ping hai chiều, FDB thường có MAC của cả hai endpoint (và có thể MAC của bridge/host nếu host gửi từ
br0).
Quan sát FDB
# Show FDB entries (needs bridge utility from iproute2)
bridge fdb show br br0
# Older alias style still seen in docs:
# bridge fdb show | grep br0
# After ping between .11 and .12, look for dynamic entries
# pointing at veth-h1 / veth-h2 (or the port ifnames you used)
| Loại entry (khái niệm) | Ý nghĩa |
|---|---|
| Dynamic (học từ traffic) | MAC endpoint vừa ARP/ping — bằng chứng path L2 sống |
| Local / self | MAC của chính bridge device |
| Permanent / static | Admin gán cố định (ít gặp lab intro) |
Trước khi ping, FDB có thể trống hoặc chưa có MAC của veth-e2. Sau một ping thành công hai chiều, bạn kỳ vọng thêm bao nhiêu MAC endpoint động — 0, 1, hay 2? Viết dự đoán, rồi bridge fdb show br br0. Không đọc man page FDB trước khi quan sát.
Kết quả kỳ vọng (mechanism): traffic hai chiều thường để lại ít nhất MAC của hai endpoint (và có thể thêm MAC host/bridge). Unknown unicast trước khi học → flood; sau khi học → unicast đúng port — đó là lý do switch scale hơn hub thuần tuý.
Liên hệ bài 01: frame trên port bridge vẫn đi softirq/sk_buff path; bridge code quyết định port egress ở L2. Gói tới IP của host trên br0 có thể local-deliver; gói giữa hai port là bridge forward L2; gói container → WAN sau đó mới là IP forward + netfilter.
5. docker0 — bridge mặc định Docker
Khi Docker dùng bridge network mặc định, daemon tạo (hoặc dùng) netdev docker0:
- Type bridge — đúng object bài này, không phải “DNS magic”.
- IP host điển hình
172.17.0.1/16(subnet mặc định có thể đổi theo config daemon). - Mỗi container: veth pair —
eth0trong netns container; đầu host tên dạngveth…vớimaster docker0. - Container-to-container cùng network: L2 qua docker0.
- Container ra ngoài: route default →
172.17.0.1, hostip_forward+ rule NAT/filter (bài 04).
# On a host with Docker engine running (illustrative)
ip link show docker0
ip addr show docker0
bridge fdb show br docker0 | head
# ip link show master docker0 # list ports enslaved to docker0
| Quan sát | Đọc gì |
|---|---|
docker0 state DOWN / missing | Daemon/network chưa lên hoặc bip khác tên |
ip link show master docker0 thiếu port container | Attach veth fail — class lỗi “IP trong container đẹp, L2 chết” |
| FDB không có MAC peer sau traffic | Port sai bridge, DOWN, hoặc traffic chưa thật sự ra wire ảo |
CNI / user-defined bridge network có thể tạo bridge khác tên (br-…) — cùng pattern: bridge + veth port + FDB + IP gateway trên bridge. Học br0 lab = đọc được docker0 production.
6. Pitfall tổng hợp
❌ Nhầm 1: “Gán IP hai đầu veth là đủ — không cần master bridge.”
✅ Hai endpoint cùng pair thì nói chuyện point-to-point không qua bridge. Muốn nhiều endpoint cùng LAN như Docker → mỗi host-side phải master <bridge>. Quên master = cáp cắm vào… không đâu.
❌ Nhầm 2: “Bridge chỉ cần tồn tại; IP trên br0/docker0 là optional luôn.”
✅ Container-to-container thuần L2 có thể không cần IP host. Nhưng path default gateway ra host/WAN cần IP trên bridge (vd 172.17.0.1). Bridge thiếu IP → “ping nhau được, ra Internet không” hoặc ARP gateway fail.
❌ Nhầm 3: “Ping container ra ngoài fail = chắc bridge hỏng.”
✅ Ra ngoài cần IP forward (net.ipv4.ip_forward=1) + netfilter NAT/FORWARD. Bridge UP và FDB đẹp vẫn fail WAN nếu forward/NAT off — tách L2 LAN vs L3 egress.
❌ Nhầm 4: “brctl là cách duy nhất / hiện đại.”
✅ brctl (bridge-utils) là legacy. Chuẩn hiện tại: ip link … type bridge + bridge (iproute2) cho FDB/vlan. Docker cũng bám netlink hiện đại.
Ba checklist trước khi đổ lỗi app:
- Port: host veth
masterđúng bridge, UP, peer container UP (bài 02). - Gateway IP:
docker0/br0có địa chỉ subnet container kỳ vọng. - Forward:
sysctl net.ipv4.ip_forward= 1 khi cần egress; rule filter/NAT xem bài 04.
Thiếu (1) = L2 gãy. Thiếu (2) = không có next-hop host. Thiếu (3) = LAN ảo sống, WAN chết.
📚 Deep Dive — man page & kernel
Spec / reference:
ip-link(8)—type bridge,master/nomaster, state.bridge(8)—bridge fdb,bridge link, VLAN filtering.- Linux bridge — kernel networking — overview bridge in kernel (khi có trong tree docs version bạn đọc).
- Docker — bridge network driver —
docker0, user-defined bridges, hành vi user-facing.
Ghi chú: Lab bài này cố ý cùng netns; production Docker thêm network namespace (module sau) nhưng lệnh master + FDB không đổi tinh thần. STP (Spanning Tree) có thể delay port — lab nhỏ thường tắt/không thấy; đừng lấy STP làm root cause trước checklist UP/master/IP.
Liên hệ các bài khác
- 00 — Tổng quan module — mảnh 3: switch ảo sau cáp veth.
- 01 — Linux network stack — softirq/
sk_buff/netfilter sau khi frame đã vào netdev (gồm port bridge). - 02 — Virtual network devices — veth pair = cáp; bài này gắn đầu host vào bridge.
- 04 — iptables và netfilter — FORWARD/NAT khi traffic đã qua veth + bridge ra ngoài host.
- Networking Foundations — từ URL tới response — path end-to-end; bài này là switch L2 trên một hop Linux.
Tóm tắt
- Linux bridge = switch L2 trong kernel: nhiều port, forward theo MAC/FDB.
- Tạo:
ip link add name br0 type bridge+up; gắn port:ip link set <dev> master br0. - veth: endpoint (container) ↔ host-side port trên bridge — mô hình Docker bridge.
- FDB học MAC từ traffic;
bridge fdb showđể chứng minh path L2. docker0= bridge mặc định + IP gateway host; cùng pattern vớibr0lab.- Pitfall: quên
master, port DOWN, bridge thiếu IP,ip_forwardoff khi cần egress — checklist L2 rồi mới netfilter. - Fade lab: port 1 worked → tự gắn port 2 → đối chiếu lời giải + ping + FDB.
7. Tự kiểm tra
Q1Vì sao Linux bridge được gọi là switch L2 chứ không phải router? Quyết định forward dựa trên trường nào?▸
Q2Lệnh tối thiểu để tạo bridge tên br0 và đưa nó sang trạng thái UP là gì?▸
ip link add name br0 type bridge (thường kèm sudo) rồi ip link set br0 up. Chỉ tạo mà không up → port/bridge admin DOWN, traffic L2 không đi.Q3Bạn có veth pair veth-h1/veth-e1. Đầu nào thường gắn master br0 trong mô hình giống Docker, và vì sao không gắn cả hai đầu?▸
veth-h1) làm port: ip link set veth-h1 master br0. Đầu còn lại là endpoint (trong lab) hoặc eth0 trong netns container — nằm “phía máy”, không phải port trên switch host. Gắn cả hai đầu vào cùng bridge sẽ làm hỏng mô hình cáp máy–switch (và không khớp Docker).Q4FDB là gì? Sau khi ping hai endpoint qua bridge thành công, bridge fdb show giúp bạn xác nhận điều gì?▸
Q5docker0 trong Docker bridge mode cổ điển tương ứng object nào trong bài lab br0? Veth đóng vai trò gì?▸
docker0 là netdev bridge (switch ảo), cùng loại br0. Mỗi container một veth pair: eth0 trong container, đầu host là port (master docker0). Container-to-container = L2 qua bridge; ra ngoài thêm gateway IP trên docker0 + forward/NAT.Q6Hai container cùng subnet ping nhau OK nhưng không ra Internet. Bridge và FDB trông lành. Bạn kiểm tra hướng nào trước — và vì sao chưa đổ lỗi 'bridge hỏng'?▸
ip_forward=1, và rule netfilter NAT/FORWARD (bài 04). Bridge không “hỏng” nếu FDB/port ổn — thiếu lớp L3/forward/NAT. Checklist: IP docker0, sysctl forward, iptables/nft counters.Q7Lab fade: đã có br0 + port veth-h1. Bạn tạo pair 2 nhưng gán IP lên veth-h2 và không set master. Ping từ veth-e1 tới IP đó fail theo hướng nào — chẩn đoán?▸
veth-h2 chưa là port bridge thì endpoint 2 không vào cùng miền L2 với port 1 qua br0. IP trên slave/port cũng sai mô hình (gateway nằm trên bridge, endpoint trên peer). Sửa: ip link set veth-h2 master br0, up đủ, IP trên veth-e2 (endpoint), không dựa IP trên host-side port.Bài tiếp theo: iptables và netfilter — tables, chains, Docker map
Bài này đáng gửi cho bạn học cùng?
Copy link đã gắn nguồn — dán group, chat, hoặc LinkedIn.
Bài này có giúp bạn hiểu bản chất không?
Hỏi đáp về bài này
Chưa có câu hỏi
Có gì chưa rõ trong bài? Đặt câu hỏi đầu tiên — câu trả lời từ cộng đồng giúp bạn (và người sau).
Đặt câu hỏi đầu tiên