Mạng Linux & Container/Virtual network devices — veth, tun, tap
3/21
Bài 3 / 21~13 phútLinux Network InternalsMiễn phí lượt xem

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:

  1. 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.
  2. Ố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).
  3. 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ườngLinux virtual deviceTầng mang gì
Cáp nhảy hai đầuveth pairL2 netdev ↔ netdev (frame qua pair)
Ống chỉ gói IPtunL3 IP packet ↔ user-space fd
Cổng Ethernet giả cho guesttapL2 Ethernet frame ↔ user-space fd
💡 Cách nhớ

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 createXoá một đầu → đầu kia biến mất / pair hỏng
State UP/DOWN theo đầuMộ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_buffDrop 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?

tuntap 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:

tuntap
Payload user ↔ kernelIP packet (L3)Ethernet frame (L2)
Device “trông như”Point-to-point / IP tunnel ifaceEthernet 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ìnhVPN (OpenVPN tun mode), một số tunnelVM 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"]
    end

Vì 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 phải tun/tap

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)

  1. Tạo veth pair.
  2. Một đầu: ip link set … netns <container> (trong netns đổi tên thành eth0, gán IP, UP).
  3. Đầu host: gắn bridge (docker0 / CNI bridge), UP.
  4. 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)

  1. Tạo tun (hoặc interface tunnel tương đương).
  2. Process VPN read packet từ tun → encrypt → gửi peer; write packet decrypt ngược vào tun.
  3. 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

  1. Hypervisor tạo tap (hoặc macvtap, vhost-net…).
  2. Guest driver thấy NIC ảo; frame ra tap trên host.
  3. Host bridge tap với phys/veth khác → guest cùng L2 với lab network.
Bài toánDevice chính“Đầu bên kia”
Container netns ↔ hostvethPeer veth (host/bridge)
Process VPN ↔ kernel IPtunUser-space VPN daemon
Guest VM ↔ host L2tapVMM process + optional bridge

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
Thử đoán

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.

⚠️ Một đầu DOWN = cáp rút một phía

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

📚 Deep Dive — tài liệu gốc

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

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 link hai 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

Tự kiểm tra
Q1
veth 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.
Q2
Vì sao gọi veth là 'cáp hai đầu' thay vì 'một interface tunnel'?
veth luôn tạo thành cặp peer trong kernel: không có fd user-space bắt buộc để giữ link, và hành vi giống cáp — gói ra đầu này vào đầu kia. Tunnel kiểu tun gắn process đọc/ghi packet; veth là hai netdev đầy đủ (MAC, bridge port, netns) nối cứng với nhau.
Q3
tun và tap khác nhau ở tầng nào? Cho một use-case khớp từng loại.
tun mang IP packet (L3) giữa kernel và user-space — hợp VPN chỉ cần route IP (OpenVPN tun, tinh thần WireGuard). tap mang Ethernet frame (L2) — hợp NIC ảo cho VM hoặc khi cần bridge L2 trên host. Không dùng tun như port bridge Ethernet thuần.
Q4
Docker bridge mode cổ điển dùng veth, tun, hay tap cho eth0 trong container? Đầu còn lại thường ở đâu?
Dùng veth pair: một đầu trong netns container (thường tên 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.)
Q5
Bạ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?
Pair cần cả hai đầu UP (và peer còn tồn tại). Đầu B DOWN = cáp rút một phía — dù A UP và có IP. 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.
Q6
Vì sao ps không giúp tìm 'process đang giữ veth' giống cách nghĩ về VPN process giữ tun?
veth pair sống hoàn toàn trong kernel networking subsystem; không có user daemon bắt buộc hold fd cho pair tồn tại. VPN tun thường có process mở /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.
Q7
Khi 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?
Khi cần mang cả miền L2 (ARP, broadcast, non-IP, hoặc bridge guest/LAN qua tunnel). tap xuất frame Ethernet để bridge/host xử lý L2. Remote access chỉ cần IP route tới subnet xa — tun gọn và đủ; tap thêm chi phí và phức tạp bridge.

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

Đặt 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

Bài tiếp theo

Linux bridge — switch L2 ảo (docker0)