Bạn có một yêu cầu không thể bẻ cong: phía xa phải nhận đúng gói IP 1,500 byte mà bên gửi phát ra, kể cả phần tiêu đề. Đường hầm không thể bọc gói đó cùng khung riêng của nó vào một gói IP 1,500 byte thứ hai, nên phải có thứ gì đó trong thiết kế nhượng bộ. Trình tự dưới đây là trình tự tôi dùng trong cửa sổ thay đổi: ghi ngân sách byte, chứng minh underlay thực sự chở được gì, sau đó chọn đúng một cơ chế vận chuyển và xác nhận gói bên trong ở phía xa.

Ghi ngân sách byte trước khi sửa hồ sơ

Đóng gói thêm byte ở nhiều tầng, và tổng số là thuộc tính của hồ sơ bạn chứ không phải hằng số có thể tra cứu. Họ địa chỉ, lựa chọn mật mã, giao thức vận chuyển và mọi tùy chọn nén hay đóng khung đều dịch chuyển con số, nên một phép trừ sao chép từ triển khai khác là vô giá trị như ngân sách. Hãy bắt đầu từ yêu cầu bên trong, cộng phần phụ trội đo được trên mỗi gói của cấu hình bạn, và ghi kích thước bên ngoài thu được vào phiếu thay đổi trước khi ai đó sửa tệp.

Hai con số quyết định thiết kế: gói bên ngoài lớn nhất mà đường đi chở được không phân mảnh, và số byte thêm mà phần đóng gói của bạn cần. Khi số thứ nhất nhỏ hơn số thứ hai cộng 1,500, một trong hai phải thay đổi. Lựa chọn khi đó trở nên hẹp chứ không sáng tạo, nên tôi ghi cả hai con số trước khi bàn các phương án. Không có gì ở tầng đường hầm nén mất những byte đó, và không một số nguyên MTU nào xóa bỏ yêu cầu bạn được giao.

Thăm dò underlay bằng ping do-not-fragment

Hãy đo đường đi thay vì tin MTU của giao diện, vì mắt xích nhỏ nhất trên đường ra ngoài mới là thứ quan trọng. Trên Linux, -M do đặt bit do-not-fragment và -s nhận tải trọng ICMP, nên khung 1,500 byte trả lời với 1,472 byte tải trọng sau khi trừ tiêu đề IP 20 byte và tiêu đề ICMP 8 byte. Tăng tải trọng cho đến khi phép thử thất bại, rồi nhảy lên kích thước jumbo để xem đường đi có chở được hay không.

ping -M do -s 1472 -c 2 198.51.100.10
ping -M do -s 8972 -c 2 198.51.100.10
tracepath -n 198.51.100.10

Một đường đi qua 1,472 và thất bại ở 8,972 không thể chở gói bên trong 1,500 byte cùng phần phụ trội trong một gói bên ngoài duy nhất. Đó là câu trả lời bạn cần trước khi mở cấu hình VPN. Nó cũng quyết định phần nào trong hai phần tiếp theo áp dụng cho bạn, nên hãy giữ cả hai kết quả thăm dò cạnh phiếu. Đoán ở đây tốn một cửa sổ bảo trì, vì một đường hầm tự báo là up không cho bạn biết gì về gói lớn nhất mà đường đi sẽ nhận.

Chỉ nâng MTU của đường đi ở nơi mọi chặng đều đồng ý

Khung jumbo là thuộc tính end-to-end, không phải một thiết lập bạn bật trên hai điểm cuối mà bạn tình cờ kiểm soát. Mọi switch, router và điểm bàn giao của nhà cung cấp trên đường ra ngoài đều phải đồng ý với kích thước lớn hơn, và một chặng 1,500 byte sẽ lặng lẽ bỏ gói bạn vừa làm lớn hơn. Chỉ nâng giao diện cục bộ là thay đổi nửa vời kinh điển khiến đường hầm trông hỏng trong khi underlay lặng lẽ đánh rơi.

ip link set dev eth1 mtu 9000
ip link show dev eth1
ping -M do -s 8972 -c 2 198.51.100.10

Đổi giao diện, rồi thăm dò lại chính đường đó trước khi đổi bất cứ thứ gì khác. Nếu phép thử vẫn thất bại, hãy hoàn nguyên bằng ip link set dev eth1 mtu 1500 và chuyển sang phân mảnh thay vì tranh cãi với nhà cung cấp về một liên kết không thuộc về bạn.

Dùng phân mảnh đường hầm khi underlay không thể lớn lên

Một cơ chế phân mảnh được hỗ trợ bên dưới gói trong cho phép nhiều gói ngoài cùng chở một gói trong, và điểm cuối đường hầm đối diện lắp chúng lại trước khi giao bản gốc cho ngăn xếp. Tùy chọn UDP fragment của Community OpenVPN là một cách hiện thực ý tưởng đó và không giống với phân mảnh IP thông thường của gói ngoài. Cả hai peer phải chạy phiên bản hỗ trợ định dạng này, và đường dữ liệu phải là đường bạn nghĩ: máy khách OpenVPN 3 và kênh dữ liệu tăng tốc bằng nhân có giới hạn khác nhau, nên một hồ sơ chạy được trên máy khách này có thể thất bại trên máy khác.

openvpn --config client.ovpn --tun-mtu 1500 --fragment 1400 --verb 4

Phân mảnh ngoài thông thường là phương án khác, và nó yếu hơn. Router IPv6 hoàn toàn không phân mảnh gói được chuyển tiếp, nên một gói ngoài quá lớn chỉ đơn giản là chết và bên gửi chỉ biết khi thông điệp ICMPv6 liên quan sống sót trên đường. Các mảnh cũng mời gọi lọc và khuếch đại mất mát, nên tôi coi đây là phương án dự phòng chứ không phải kế hoạch.

Một bộ chở ngoài dựa trên luồng né câu hỏi kích thước bằng cách phân đoạn luồng byte của chính nó, và gói trong được tái tạo vẫn có thể là 1,500 byte. Đó là quyết định vận chuyển có chi phí riêng, kể cả hành vi TCP trong TCP quen thuộc, nên hãy chọn nó có chủ đích chứ không phải như tác dụng phụ của một cuộc tranh luận về MTU.

Xác nhận gói bên trong đến nguyên vẹn

Kiểm chứng không phải là một handshake thành công. Bắt gói trên giao diện đường hầm ở cả hai đầu và so sánh kích thước, nội dung của gói ứng dụng thực sự gửi với gói phía xa nhận được.

ip link show dev tun0
ping -M do -s 1472 -c 2 10.8.0.1
tcpdump -ni tun0 -c 5 'icmp and greater 1000'

Nếu bản bắt gói cho thấy gói trong đủ kích thước ở đầu kia, lựa chọn vận chuyển đã đúng và việc còn lại là ghi lại. Nếu nó không cho thấy gì trong khi đường hầm tự báo up, gói ngoài đang bị bỏ ở đâu đó giữa hai điểm cuối, điều này đưa bạn trở lại phép thăm dò chứ không phải cấu hình mật mã.

Ghi ba thứ vào phiếu thay đổi trước khi đóng: ngân sách bên ngoài đo được, cơ chế bạn chọn và lệnh đã chứng minh gói trong sống sót. Người tiếp theo chạm vào đường hầm này sẽ cần cả ba, và không thứ nào có thể dựng lại chỉ từ tệp cấu hình.

Bài viết liên quan