BIG TCP 這條超大段路徑從 2022 年進 kernel 5.19 開始處理 IPv6,到 kernel 6.3 補上 IPv4,中間差不多三年,單包能一路放大到 185 KB,TSO 跟 GRO 的開銷按比例下降,25G 以上的網卡才算真的用得起 Linux 的通用網路堆疊。但有一條支路一直沒接通:UDP 隧道。VXLAN 跟 Geneve 這兩個 overlay 網路的主力協定走 UDP 封裝,Linux 7.3 這版把這條缺口補起來——tso_max_size 一路升到 GSO_MAX_SIZE,udp_gro_receive 的長度檢查改成允許 uh->len=0 的大封包聚合,雲上跑 Cilium、Flannel VXLAN、OVN 的 Kubernetes 叢集這才算真的拿到完整的 BIG TCP 收益。
這個改動不新鮮——這套 patch set 從 2025 年 9 月第一輪開始投,中間經過 v2 到 v9 九輪 review,才在 2026 年 7 月進入 net-next,隨後跟著 Linux 7.3 的 merge window 進主線。Ubuntu 26.10 以 7.3 當基礎核心,這也是為什麼跑在 VPS 上的 Kubernetes overlay 網路這幾個月要盯著版本編號看。
BIG TCP 原本卡在哪裡
TSO (TCP Segmentation Offload) 跟 GRO (Generic Receive Offload) 這兩個 offload 機制把分段的事情交給 NIC 處理,上層只要給一個大 skb,中斷數、CPU 處理時間都能壓低。問題是傳統 TCP 單包長度欄位 16 bit,上限 65535 位元組,TSO/GRO 的通用上限也就卡在 64K。這個數字在 1Gbit 時代沒感覺,到了 25、40、100Gbit 線速,每秒要處理的 skb 數量翻幾個數量級,光是 skb 配置跟 metadata 搬動就把 CPU 吃光,大批次處理的優勢被 header 開銷稀釋掉。
IPv6 的 Jumbogram 擴充頭是 RFC 2675 寫了二十多年的東西,用 hop-by-hop 32 bit 長度欄位把單包撐到 4 GiB。Linux 5.19 把這條路打開:發送端加 hop-by-hop header、接收端讀出來還原 skb。IPv4 沒有這麼乾淨的擴充空間,kernel 6.3 用的做法是在 IP header 的 tot_len 寫 0,skb 內部用 TSO 大小當真實長度,驅動層再處理。這條路徑在直接路由(不包隧道)的工作負載上已經能跑了,兩種協定的差異抹平了。
但 overlay 網路這條路一直走不過去。VXLAN 跟 Geneve 都把乙太網幀塞進 UDP payload,kernel 的 UDP 隧道程式碼在 GRO 聚合時會檢查 UDP header 的 length 欄位,長度跟實際 skb 長度不對會被排除。BIG TCP 的大包根本過不了這道檢查,tso_max_size 在 VXLAN、Geneve 的 netdev 預設也沒超過 65536,offload 進不去,大 skb 一到 tunnel egress 就被切回 64K 以內。
這表示:跑 Cilium VXLAN overlay 的 Kubernetes 叢集,Pod-to-Pod 的 TCP 吞吐就算底下 25G NIC 支援 TSO/GRO BIG TCP,實際走出去還是 64K 分段,CPU 使用率跟延遲都比直接路由差一截。這個 gap 在雲上 overlay 普遍部署的今天越來越明顯,社群抱怨了好幾年。
7.3 做了什麼
這一版的改動核心有三塊。
一是 UDP header 的長度處理改成走 accessor。新增 udp_set_len() 跟 udp_hdr_len() 這類介面,BIG TCP 大於 65535 的 UDP 封包把 uh->len 填 0,實際長度從 skb 本身讀。這是對齊 IPv4 BIG TCP 的做法——IP 層已經接受「header 寫 0、實際長度用 skb」的語意,UDP 層現在也跟上。
二是 GRO 聚合邏輯放寬。udp_gro_receive 原本會把長度 0 的封包視為異常直接排除,現在改成只排除還沒聚合完的那些。udp_gro_complete() 在聚合後的封包總長度大於等於 GRO_LEGACY_MAX_SIZE(65536)時主動把 uh->len 寫 0,接收端重組就跟直接路由的 BIG TCP 走同一條語意路徑。
三是 driver 層。VXLAN 跟 Geneve 的 netdev 註冊時原本把 tso_max_size 設在 65536,現在改用 netif_set_tso_max_size(dev, GSO_MAX_SIZE)。GSO_MAX_SIZE 預設是 185000 位元組,但實際上限受底下 NIC 的 tso_max_size 限制——如果底下的實體 NIC 回報的最大值小於這個,tunnel netdev 會被壓到 NIC 的值。
結果就是:overlay 封裝不會再是 BIG TCP 的終點。大 skb 在 Pod 的 TCP 層生成,走過 Cilium 的 eBPF datapath,進 VXLAN encap,直接以單個大 skb 交到 NIC,由 NIC 把 inner header 跟 outer UDP/IP header 一起分段送出。接收端 GRO 把 UDP tunnel 流量聚合回大 skb,交給上層 TCP。
25G 以上網卡才看得到差距
要享受到這個改動的收益,有幾個前提條件得全部到位。
NIC 要支援 UDP tunnel segmentation offload(tx-udp_tnl-segmentation),而且 tso_max_size 要大於 65536。資料中心等級的 25G、100G 網卡——Mellanox ConnectX-5 以上、Intel E810、Broadcom BCM57508 這類——大部分都報 65535 或更高,有的能到 524280。消費級跟虛擬網卡(virtio-net、xen-netback)在這一塊的支援度看版本,不一定吃得到。
網路堆疊兩端都要跑 7.3 以上,而且中間不能有把大 skb 切回 64K 的中介——像是某些 OVS userspace datapath、網管設備的 MTU 限制、不支援 UDP tunnel offload 的 CNI。發送端跟接收端一起升上去,差距才會明顯。
典型場景的實測差距:Pod-to-Pod 單流 TCP 從 15 Gbps 左右拉到接近線速(22-24 Gbps on 25G NIC),CPU 使用率從 60% 以上壓到 20-25%。數字會隨 workload 跟 CPU 架構變,但「不受 overlay encap 限制」這件事是真的開始成立。
1G、10G 環境下的收益不明顯——那個速度 CPU 本來就吃得消 64K 分段,BIG TCP 的優勢要到 25G 以上才會被放大出來。
Cilium 的驗證坑
Cilium 這邊已經在同步跟進,但 GitHub 上有個已知問題(issue #46337):如果底下的 NIC advertise 的 tso_max_size 太大——有的網卡會報 524280——Cilium 嘗試把這個值直接套到 VXLAN netdev 時會被 kernel 拒絕,噴 Invalid argument。原因是 Cilium 這段邏輯寫在 BIG TCP for UDP tunnels 合進去之前,當時 VXLAN 的上限硬在 65536,驗證邏輯沒跟上新的語意。
目前的 workaround 是手動把實體 NIC 的 gso_max_size 透過 ethtool 或 ip link set 壓到一個 Cilium 能接受的值(例如 65536 或 131072),讓 Cilium 的 VXLAN 設定能過;或者等 Cilium 的 fix 進下一個 minor release。對運維來說要注意的是:升到 7.3 之後觀察 Cilium agent 的 log,看到 tso_max_size 相關的 Invalid argument 錯誤要去回查。
Geneve 這邊的 driver 改動一樣已經在 7.3 裡,但 OVN 跟 Istio Ambient Mode 這類主要跑 Geneve 的場景目前的 config layer 還沒完全對接。Flannel VXLAN 這邊相對乾淨,社群沒有卡住的 PR。
MTU 跟 PMTUD 要重新算
BIG TCP 本質上是「kernel 內部的大 skb」,到 NIC 分段後出去的仍然是符合 path MTU 的封包。但 overlay 這條路得多考慮一層 encap overhead——VXLAN 50 bytes、Geneve 基本 50 bytes、加 options 更多。underlay 支援 jumbo frame(9000 MTU)的話,overlay inner MTU 可以設到 8900 以上,BIG TCP 的收益才能完整發揮;underlay 卡在 1500 MTU 的話,inner 得往下砍到 1450 以下,每個封包都在 1500 以下,大 skb 進 NIC 一樣會被切成一堆小封包,雖然節省了 skb 搬動的 CPU,但網路效率不如 underlay jumbo。
PMTUD 的黑洞在 overlay 環境本來就不好處理,升到支援 BIG TCP 的 kernel 之後更要盯著——icmp6_errors 跟 IcmpInDestUnreachs 的 counter 走勢,可以及早發現有中介設備把 ICMP Too Big 擋掉。
升級前的檢查清單
對於自建 K8s on VPS 的場景,7.3 進 production 之前有幾件事要先盤:CNI 版本要對齊——Cilium 1.17、1.18 的 bugfix 版本有在收這個改動,Calico 跟 Flannel 的狀態要分別確認。網卡 driver 要用上游 in-tree 的新版,out-of-tree 的 OEM driver 不保證支援 UDP tunnel offload 的新語意。監控上要加 ethtool -S 的 tunnel-related counter 跟 Node 的 /proc/net/snmp6,覆蓋 regression。
Ubuntu 26.10 預計 2026 年 10 月 15 日釋出,直接帶 Linux 7.3——這會是第一波大規模驗證。Debian 這邊 trixie 的 backport 要等一段時間,RHEL 10 的 ELS kernel 不會回補這個 feature。想在生產環境踩的,先在 staging 用 25G 以上網卡的節點拉 iperf3 跟 Pod-to-Pod 的 benchmark,確認數字真的拉上去再推 rollout。
overlay 網路的 TCP 吞吐在 Linux 上拖了幾年,7.3 把這條最後一公里補起來。對於跑在臺灣機房、底層走 25G 以上 IP Transit 的 K8s 叢集,升到支援 BIG TCP 的 kernel 之後,overlay 的 CPU 跟延遲曲線會明顯平滑一截。NCSE Network 在臺灣是方電訊機房提供 Intel Gold CPU、NVMe SSD 的 VPS 以及 10M 到 100G 的 IP Transit,是跑高吞吐 overlay 網路跟自建 Kubernetes 叢集的合適選擇,服務規格可以到 ncse.tw 查看。