2016年7月21日 星期四

使用 GRE Tunnel 時,可能會遇到的 MTU 問題

From:http://teenyscrew.blogspot.tw/2014/06/gre-tunnel-mtu.html

一般來說,Ethernet 的 MTU (Frame 除了 header 以外的 Palyload) 是 1500 Bytes, Header  + Tailer 則是 14 Bytes

這 1500 bytes 包含了 

  1. IP 層 Header (固定 20 Bytes)
  2. TCP / UDP 層 Header  (固定 20 Bytes)
  3. TCP / UDP 層 Payload (變動)
對 TCP 來說,在三方交握時,兩方會針對第三點的大小進行協議,得到的數值就是 MSS

因為 Ethernet MTU 一般是 1500 Bytes,扣掉固定大小的 IP Header 以及 TCP Header 之後,


得到的 1460 Bytes 就是在一般情況之下,MSS 能夠達到的最大值。


因此 TCP 在進行三方交握時,一般都假設自己的 MSS 是 1460 Bytes。



好,MTU 的觀念整理完了,接下來要說 GRE Tunnel。


GRE Tunnel 是把封包原封不動的在前面另外加上 GRE Header,而這個 Header 總計 24 Bytes*。


所以一個 TCP / IP Packet ( MSS=1460 ),送到 GRE Tunnel Router 後,再加上 GRE Header 會變成

1460 + 20 + 20 + 24 = 1524 Bytes
冰崩,問題來了,就算是 GRE Tunnel 的封包,最終還是要從實體端口傳送出去,

Ethernet MTU 是 1500 Bytes ,所以封包若要傳送一定要經過 Fragmentation,如果封包加上 DF,則傳送就會失敗。


要避免 fragmentation 的問題,其中一個方法是減少 MSS ,讓封包加上 GRE Header 之後還能在 1500 Bytes 以下。


因此這個 MSS 應該小於或等於

1500 - 24 - 20 - 20 = 1436
這也是為什麼 GRE Tunnel MTU 預設會是 1436 + 20 + 20  = 1476 Bytes 了


至於修改 MSS 的方式有幾種,

  1. 主機上修改。很不方便,不建議
  2. Router 攔截 TCP Connection 後修改 MSS Value : ip tcp adjust-mss 1436(設定在 int tunnel)(註)
在 windows 用 ping 指令測試時,要注意的是,當我們用 -l  指令來指定封包大小時,這個大小其實只包含了 icmp data 欄位,也就是尚不包含 icmp header **,更不包含 ip header。所以對 MTU = 1500 bytes 的Ethernet 來說,icmp 封包超過 1500 - 20 - 8 = 1472 時,封包就無法傳送出去了。(前提是測試時有設定DF bit)如
 ping 168.95.1.1 -l 1472 -f 
但在 cisco device 上作 ping test 時,指定的 packet size 其實是包含了 ip header + icmp header + icmp data。所以做測試時,packet size 最大可以設定成 1500。超過此數值,又同時設定 df-bit 則封包會無法傳送***。

最後要注意的是,IPv6 header size 是 40 bytes,所以一般狀態下 MSS 應該是 1500(MTU) - 40(IPv6 Header) - 20(TCP Header) = 1440 bytes。在 GRE Tunnel 狀態下,MSS 等於 1500 - 24 - 40 - 20 = 1416 bytes(比 IPv4 小 20 bytes)。

 * 更嚴格來說 4 Bytes 係來自於 GRE 的 4 Bytes 與新的 IP Header 20 Bytes。因為 New IP Packet  = new ip header + gre header + original ip packet。by the way, Dynamic Multipoint VPN (DMVPN) using GRE Header 是 26 Bytes。

** ICMP 封包的完整格式包括:ethernet header + ip header + icmp header。所以 icmp 不屬於二層也不屬於三層,但是又需要 IP 來協助傳送。

*** 引用 Cisco Forum 上一個 CCIE 工程師的回答

In IOS, when you specify the size, that is the overall packet length.  So if you specify size 250, the packet will be 250 bytes.  In windows, ping -l specifies the ICMP data.  So -l 250 produces a 278 byte IP packet.  This is calculated as 250 bytes of data + 8 bytes of ICMP header + 20 bytes of IP header.  I just wanted to make the distinction as to what size meant in IOS as opposed to Windows.
註 有篇文章說 IPv6 的指令,IOS version 必須在 15.2(4)M 之後才有,但是我測試結果是不行,或許跟 License 有關?


2014-07-07 更新
經網路上前輩提醒,該文章說的 ipv6 tcp adjust-mss 指令,只有在 ASR 才會出現,所以我用 ISR 試一輩子也沒用。不過原本的 IP tcp adjust-mss 指令就可以滿足我的條件,因為他會同時修改 IPv6 and IPv4 TCP MSS。早上做了實驗的確是這樣,用 Wireshark 看三方交握的封包,的確改成我設定的 1220 Bytes。(測試用,依據最小 MTU 1280 byte計算得來)

參考文章
http://networklessons.com/ip-routing/pppoe-mtu-troubleshooting-cisco-ios/
http://www.cisco.com/c/en/us/support/docs/ip/generic-routing-encapsulation-gre/13725-56.pdf
http://itchenyi.blog.51cto.com/4745638/1137143
http://blog.thousandeyes.com/troubleshooting-path-mtu-tcp-mss-problems/
http://switchpacket.blogspot.tw/2014/07/understanding-difference-between-mtu.html