Virtual network devices — veth, tun, tap
Vì sao cần thiết bị mạng ảo: veth pair như cáp 2 đầu, tun vs tap (L3 vs L2), và chỗ chúng xuất hiện trong container, VPN, VM.
TL;DR: Kernel Linux không chỉ có eth0 vật lý. veth pair là hai interface ảo luôn dính nhau — gói ra đầu A hiện ngay đầu B như cáp hai đầu, nền của hầu hết container network. tun đưa gói IP (L3) vào user-space; tap đưa frame Ethernet (L2) — VPN kiểu WireGuard/OpenVPN hay dùng tun (hoặc giao thức riêng), VM và bridge ảo hay dùng tap. Tạo veth bằng ip link add … type veth; pitfall kinh điển: một đầu DOWN thì traffic “biến mất” dù đầu kia UP và IP đã gán.
Sprint review: demo container-to-container “chạy mượt trên máy dev”. Trên staging, ping giữa hai pod timeout. Junior đã ip addr trong netns — IP đúng, route có gateway. Bạn hỏi: “hai đầu veth đều UP không?” Một đầu gắn bridge host còn DOWN sau script attach. ip link set … up hai đầu → ping sống. Không phải DNS, không phải app — cáp ảo một đầu rút.
Bài 01 — Linux network stack vẽ path gói trong kernel khi đã có device. Bài này giải thích device ảo kernel tạo ra để nối netns, VPN process, và hypervisor guest — cùng stack sk_buff/softirq, chỉ khác “cổng” vào/ra.
Bài này giải thích cơ chế bên dưới veth/tun/tap và khi nào chọn loại nào, trước khi bridge ghép nhiều veth thành LAN ảo.
1. Analogy — Cáp nhảy, ống IP, và cổng Ethernet ảo
Ba món đồ trên bàn lab:
- Cáp nhảy (patch cable) hai đầu RJ45 — cắm switch này với switch kia. Tháo một đầu → cả “đường” chết dù đầu còn lại còn cắm.
- Ống hút chỉ cho gói thư đã dán tem IP — không quan tâm phong bì Ethernet; ai ngồi user-space “hút” gói IP ra xử lý (mã hoá, forward).
- Cổng Ethernet giả gắn vào máy ảo — guest thấy “card mạng”, host thấy một interface có thể bridge như cổng switch thật.
| Đời thường | Linux virtual device | Tầng mang gì |
|---|---|---|
| Cáp nhảy hai đầu | veth pair | L2 netdev ↔ netdev (frame qua pair) |
| Ống chỉ gói IP | tun | L3 IP packet ↔ user-space fd |
| Cổng Ethernet giả cho guest | tap | L2 Ethernet frame ↔ user-space fd |
veth = cáp hai đầu trong kernel (không cần process user “giữ” cáp). tun/tap = cửa sổ mở ra process user-space: tun nhìn IP, tap nhìn Ethernet. Container = chủ yếu veth; VPN process = chủ yếu tun; VM = chủ yếu tap.
2. veth pair là gì — vì sao gọi là cáp ảo hai đầu?
veth (Virtual ETHernet) là loại netdev kernel: khi tạo, bạn luôn tạo một pair — hai interface, mỗi cái có tên riêng (ví dụ veth0 / veth1, hoặc veth-host / veth-c1). Kernel gắn chúng thành peer:
- Frame transmit ra đầu A → xuất hiện như receive trên đầu B (và ngược lại).
- Không cần “dây” user-space; không cần process giữ fd để pair tồn tại (khác tun/tap gắn process).
- Mỗi đầu là netdev đầy đủ: có MAC, state UP/DOWN, có thể gán IP, gắn bridge, đưa vào network namespace khác.
flowchart LR
NS_A["Netns A / host"] --> VA["veth A"]
VA -->|"peer TX/RX"| VB["veth B"]
VB --> NS_B["Netns B / container"]Đó là lý do Docker bridge mode “ma thuật”: container có eth0 (thường là một đầu veth đã move vào netns container); đầu còn lại nằm trên host (tên dạng veth…) và gắn vào bridge docker0. Gói container → eth0 → peer host → bridge → (routing/NAT) → ra ngoài. Chi tiết bridge ở bài 03; ở đây chỉ cần: không có veth pair thì không có “cáp” nối netns với host stack.
Vì sao không chỉ gán IP trên loopback?
lo chỉ nói chuyện trong cùng netns. Hai netns (host vs container) là hai “máy logic” — cần device để gói rời netns này sang netns kia. veth là cách kernel cung cấp link point-to-point L2 giữa hai netns (hoặc cùng netns — vẫn hợp lệ, ít dùng production).
| Đặc điểm | Ý nghĩa debug |
|---|---|
| Peer cố định lúc create | Xoá một đầu → đầu kia biến mất / pair hỏng |
| State UP/DOWN theo đầu | Một đầu DOWN = cáp rút một phía |
Có stats riêng (ip -s link) | RX/TX trên A phản ánh traffic peer B |
Cùng path softirq/sk_buff | Drop vẫn đọc như bài 01 — chỉ thêm “device ảo” |
3. tun và tap khác nhau thế nào — L3 packet vs L2 frame?
tun và tap là driver tạo netdev gắn với file descriptor user-space (/dev/net/tun). Process đọc/ghi fd = “gói vào/ra” stack kernel qua device đó.
Khác biệt cứng nằm ở tầng payload kernel kỳ vọng:
| tun | tap | |
|---|---|---|
| Payload user ↔ kernel | IP packet (L3) | Ethernet frame (L2) |
| Device “trông như” | Point-to-point / IP tunnel iface | Ethernet NIC (có MAC) |
| Bridge L2 trực tiếp? | Không (không phải Ethernet port) | Có — gắn Linux bridge |
| Use-case điển hình | VPN (OpenVPN tun mode), một số tunnel | VM NIC, QEMU, bridge lab, OpenVPN tap mode |
flowchart TB
subgraph TUN_PATH["tun path"]
APP1["User process"] -->|"read/write IP"| TUN["tun0"]
TUN --> STACK1["IP stack host"]
end
subgraph TAP_PATH["tap path"]
APP2["User process / VMM"] -->|"read/write Ethernet"| TAP["tap0"]
TAP --> STACK2["L2 / bridge / IP"]
endVì sao tách hai loại?
Stack IP host đã biết route gói IP; VPN chỉ cần nhận IP packet, mã hoá, gửi đi UDP/TCP — tun đủ, gọn, không giả lập Ethernet. Guest VM lại giả lập card Ethernet đầy đủ (ARP, broadcast, nhiều IP trên một “LAN”) — hypervisor cần tap (hoặc vhost tương đương) để guest gửi frame, host có thể bridge các tap như cổng switch.
OpenVPN hỗ trợ cả hai mode: dev tun vs dev tap — chọn sai mode = “VPN lên nhưng không bridge LAN” hoặc ngược lại. WireGuard trên Linux tạo interface kiểu tunnel L3 (gần tinh thần tun, API riêng wg) — vẫn là “user/kernel đưa IP packet”, không phải veth pair.
veth không mở /dev/net/tun cho app. Cả hai đầu sống trong kernel; process chỉ send/recv qua socket trên IP đã gán (hoặc bridge forward). Đừng tìm “process giữ veth” trong ps — hãy ip link và netns.
4. Khi nào dùng veth, tun, hay tap — container, VPN, VM?
Ba bài toán — ba lớp device (đôi khi kết hợp):
Container (Docker bridge / CNI bridge)
- Tạo veth pair.
- Một đầu:
ip link set … netns <container>(trong netns đổi tên thànheth0, gán IP, UP). - Đầu host: gắn bridge (
docker0/ CNI bridge), UP. - Route/NAT host (netfilter) cho traffic ra ngoài — bài 04.
Không bắt buộc tun/tap cho path bridge cổ điển. (Có plugin/special path khác; blueprint module bám veth + bridge.)
VPN (userspace)
- Tạo tun (hoặc interface tunnel tương đương).
- Process VPN
readpacket từ tun → encrypt → gửi peer;writepacket decrypt ngược vào tun. - Route table trỏ prefix remote vào
tun0.
Cần “gom cả Ethernet LAN qua VPN” (bridge domain) → cân nhắc tap + bridge — nặng và hiếm hơn path IP-only.
VM / emulator
- Hypervisor tạo tap (hoặc macvtap, vhost-net…).
- Guest driver thấy NIC ảo; frame ra tap trên host.
- Host bridge tap với phys/veth khác → guest cùng L2 với lab network.
| Bài toán | Device chính | “Đầu bên kia” |
|---|---|---|
| Container netns ↔ host | veth | Peer veth (host/bridge) |
| Process VPN ↔ kernel IP | tun | User-space VPN daemon |
| Guest VM ↔ host L2 | tap | VMM process + optional bridge |
5. Tạo veth pair bằng ip link như thế nào?
Chạy trên Linux (VM/WSL2/host), thường cần sudo. Mục tiêu: thấy pair, stats peer, và hiệu ứng một đầu DOWN.
# Create a veth pair with explicit names on both ends
sudo ip link add veth-a type veth peer name veth-b
# Both exist; admin state often DOWN until you up them
ip link show veth-a
ip link show veth-b
# Bring BOTH ends up (classic pitfall: only one side)
sudo ip link set veth-a up
sudo ip link set veth-b up
# Optional: assign addresses on the same L2 link (same netns demo)
sudo ip addr add 10.200.0.1/24 dev veth-a
sudo ip addr add 10.200.0.2/24 dev veth-b
# Ping peer through the virtual cable
ping -c 2 10.200.0.2
# Counters: TX on one end ~ RX on the other
ip -s link show veth-a
ip -s link show veth-b
# Cleanup when done
# sudo ip link del veth-a
# deleting one end removes the pair
Sau khi cả hai đầu UP và ping OK, bạn sudo ip link set veth-b down rồi ping lại 10.200.0.2 từ host (nguồn qua veth-a). Ping còn sống, fail ngay, hay treo? Viết dự đoán — rồi chạy. Không gán thêm IP hay restart network trước khi quan sát.
Kết quả kỳ vọng (mechanism): peer down → path L2 gãy; ping fail (unreachable / no reply tùy stack và địa chỉ). veth-a có thể vẫn UP và giữ IP — state một đầu không cứu được đầu kia DOWN. Production container: đầu host DOWN hoặc không attach bridge = đúng class lỗi “IP trong container đẹp, traffic chết”.
Gắn nhanh với netns (preview Module 2)
# Illustrative only — full netns lab comes in later modules
# sudo ip netns add demo
# sudo ip link set veth-b netns demo
# sudo ip netns exec demo ip link set veth-b name eth0
# sudo ip netns exec demo ip link set eth0 up
# sudo ip netns exec demo ip addr add 10.200.0.2/24 dev eth0
# Host keeps veth-a; container netns owns the peer as eth0
Ở module này chỉ cần hình dung: move một đầu sang netns khác = cắm cáp sang “máy” logic khác; đầu còn lại vẫn trên host để bridge/NAT.
6. Pitfall tổng hợp
❌ Nhầm 1: “Chỉ cần ip link set veth-a up.”
✅ Pair có hai admin state. Container “lạ” thường do đầu host quên up hoặc script fail giữa chừng. Checklist: ip link cả hai tên (trong netns + trên host).
❌ Nhầm 2: “tun và tap thay nhau được — đều là tunnel.”
✅ Tầng payload khác nhau. Bridge L2 cần tap (hoặc veth); route IP-only VPN thường tun. Chọn sai = ARP/broadcast không đi hoặc user-space parse sai header.
❌ Nhầm 3: “veth là process user-space như VPN.”
✅ veth là kernel peer. Không có daemon “giữ cáp”. Hạ ip link del một đầu = cắt pair. Debug bằng ip/netns, không bằng ps | grep veth.
❌ Nhầm 4: “Ping fail = iptables chắc chắn.”
✅ Trước netfilter sâu, xác nhận carrier logic: device tồn tại, cả hai đầu UP, peer đúng netns, (sau này) port bridge UP. Bài 01 đã dạy multi-layer drop — device DOWN là drop trước khi nghi MASQUERADE.
Triệu chứng: IP/route trong container trông đúng; tcpdump một phía im hoặc chỉ thấy ARP fail. Nguyên nhân hay gặp: attach script up sai thứ tự, rename interface, hoặc tool xóa nhầm peer. Fix thao tác: ip link set <both> up + kiểm tra peer vẫn tồn tại (ip link không “Device not found”).
📚 Deep Dive — man page & kernel
Spec / reference:
ip-link(8)—type veth,peer name, state, move device.- Linux TUN/TAP —
/dev/net/tun, IFF_TUN vs IFF_TAP, userspace API. veth(4)— virtual ethernet pair: peer semantics, lifecycle.
Ghi chú: Đọc man ip-link khi tạo/xóa device; đọc tuntap khi viết/đọc VPN hoặc gắn QEMU. Bridge attach (master/bridge) để bài 03.
Liên hệ các bài khác
- 00 — Tổng quan module — mảnh 2 trên bản đồ bốn plumbing.
- 01 — Linux network stack — gói qua softirq/
sk_buff/netfilter sau khi đã vào một netdev (gồm veth/tun/tap). - 03 — Linux bridge — gắn đầu host của veth (và tap) vào switch L2 ảo
docker0. - 04 — iptables và netfilter — FORWARD/NAT khi traffic đã qua veth + bridge ra ngoài.
- Networking Foundations — từ URL tới response — path end-to-end; bài này là cáp/cửa ảo trên một hop Linux.
Tóm tắt
- veth pair = cáp L2 hai đầu trong kernel; TX A = RX B — xương sống container netns ↔ host.
- tun = cửa L3 (IP) cho process user-space (VPN); tap = cửa L2 (Ethernet) cho VM/bridge.
- Ba use-case: container → veth; VPN process → tun; VM → tap (+ bridge).
- Tạo pair:
ip link add … type veth peer name …rồi up cả hai, gán IP hoặc move netns / master bridge. - Pitfall số một: một đầu DOWN hoặc xoá nhầm peer — luôn
ip linkhai phía trước khi đổ lỗi app/iptables. - Cùng network stack bài 01; device ảo chỉ đổi cổng vào stack, không thay softirq/
sk_buff.
7. Tự kiểm tra
Q1veth pair khác loopback (lo) ở điểm nào khi bạn cần nối host với network namespace của container?▸
lo chỉ giao tiếp trong cùng netns. Container và host là hai netns khác nhau — cần netdev đưa frame/gói ra khỏi netns. veth pair tạo hai đầu có thể nằm hai netns; peer kernel đảm bảo TX một đầu thành RX đầu kia. Không có pair (hoặc đường tương đương), hai netns không có L2/L3 link với nhau.Q2Vì sao gọi veth là 'cáp hai đầu' thay vì 'một interface tunnel'?▸
Q3tun và tap khác nhau ở tầng nào? Cho một use-case khớp từng loại.▸
Q4Docker bridge mode cổ điển dùng veth, tun, hay tap cho eth0 trong container? Đầu còn lại thường ở đâu?▸
eth0), đầu host gắn bridge docker0 (tên veth…). Không phải path tun mặc định. (CNI/plugin khác có thể khác; model chuẩn bridge Docker là veth + bridge.)Q5Bạn ip link set veth-a up và gán IP, ping peer không được. ip link show veth-b báo state DOWN. Chẩn đoán và bước sửa tối thiểu?▸
ip link set veth-b up (và đảm bảo địa chỉ/route đúng). Nếu B missing, pair đã bị xoá — tạo lại pair, không chỉ up A.Q6Vì sao ps không giúp tìm 'process đang giữ veth' giống cách nghĩ về VPN process giữ tun?▸
/dev/net/tun và đọc/ghi packet. Debug veth bằng ip link, netns, bridge port — không bằng tìm PID tên veth.Q7Khi nào bạn cân nhắc tap thay vì tun cho VPN/lab, dù tun phổ biến hơn cho remote access IP?▸
Bài tiếp theo: Linux bridge — switch L2 ảo (docker0)
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