大家好python
在《MTU工具解析與常見問題彙總-上篇》中,咱們一塊兒討論了MTU的基本定義,以及數據包分片的具體細節,同時也簡單列舉了MTU不匹配致使的問題和對網絡數據傳輸的危害。api
既然MTU問題多多,那麼儘量避免由MTU引起的網絡問題將顯得尤其重要。一般而言,咱們可使用如下方法來檢測和避免MTU問題:安全
1. 手工測試發現MTU值服務器
2. TCP-MSS網絡
3. PathMTU Discoverytcp
今天咱們就來聊聊以上工具的具體細節以及如何經過他們發現鏈路MTU的最佳值,同時奉上兩個典型的由MTU引起的問題案例。ide
什麼是最佳MTU值?工具
最佳MTU值,是指保證數據包不被分片的狀況下,以字節爲基本單位的鏈路單個數據包尺寸的最大臨界值。若是數據包再多一個字節長度,數據包就會被分片。此值稱爲最佳MTU值。性能
爲了演示常見MTU檢測方法,特搭建網絡測試環境以下:測試
上圖網絡拓撲中,存在兩個網絡站點A和B。A站點和B站點能夠經過ISP運營商互聯互通。
A站點出口路由器爲SRX01,出口IP爲1.1.1.1
B站點出口路由器爲SRX02,出口IP爲2.2.2.2
站點A和站點B出口路由器的MTU值以下:
A站點的出口MTU值爲巨型MTU值9000字節。
B站點的出口MTU 值爲2000字節。
在A,B站點各有公網服務器一臺:
A站點Server 7, IP:3.3.3.3
B站點Server 8, IP:4.4.4.4
二者能夠經過ISP的BGP路由互聯互通。
此場景存在的問題爲:運營商內核心路由器之間的MTU值未知。但因爲網絡通訊是一個端到端的總體行爲,若不經過某種方法獲悉運營商之間的鏈路MTU值。那A和B之間的通訊可能存在數據包分片甚至丟包的行爲。
在開始研究如何發現端到端的鏈路最優MTU值以前,讓咱們先作一個簡單的Ping聯通性測試以確保SRX01和SRX02可以正常通訊。
lab@SRX01>ping 2.2.2.2 source 1.1.1.1 rapid count 5 PING2.2.2.2 (2.2.2.2): 56 data bytes !!!!! --- 2.2.2.2ping statistics --- 5 packets transmitted, 5 packets received, 0% packet loss round-tripmin/avg/max/stddev = 21.491/32.152/37.884/6.149 ms lab@SRX01> lab@SRX01>traceroute 2.2.2.2 source 1.1.1.1 tracerouteto 2.2.2.2 (2.2.2.2) from 1.1.1.1, 30 hops max, 40 byte packets 1 1.1.1.100 (1.1.1.100) 12.050ms 8.905 ms 14.453 ms 2 35.0.0.5 (35.0.0.5) 41.774ms 21.306 ms 22.849 ms 3 2.2.2.2 (2.2.2.2) 42.211 ms 29.103 ms 35.168 ms
Ping包成功,兩端鏈路通訊正常。經過Traceroute能夠看出穿越的運營商路由器IP地址。
注:上圖中,默認狀況下,Juniper的Ping包負載尺寸爲56字節。
服務器連通性測試:
環境確認測試完成,讓咱們來逐一介紹MTU的發現方式:
最簡單也是最直觀的MTU檢測方式天然是手工測試。
手工測試提供了其餘工具沒法比擬的優點:可視性,直觀性。
讓咱們來看看如何經過手工測試法發現鏈路的MTU值。
lab@SRX01> ping 2.2.2.2 source 1.1.1.1 rapid count 1 do-not-fragment size 8000 PING 2.2.2.2 (2.2.2.2): 8000 data bytes 36 bytes from 1.1.1.100: frag needed and DF set (MTU 1500) Vr HL TOS Len ID Flg off TTL Pro cks Src Dst 4 5 001f5c c999 2 0000 40 014c02 1.1.1.1 2.2.2.2 . --- 2.2.2.2 ping statistics --- 1 packets transmitted, 0 packets received, 100% packet loss
針對上面的Ping測試,有幾點須要說明:
1. Do-not-fragment關鍵字很重要,在《MTU共計解析與常見問題彙總-上篇》中曾經提到過,發送方能夠自主肯定數據包是否須要被分片。而決定的方法爲設置DF=1,告知下游路由器請不要對數據包進行分片。在此測試案例中,我指定了do-not-fragment。顧名思義,SRX01會根據個人要求把ICMP包的DF設置爲1。
2. Size 8000是告知SRX01請產生一個8000字節的載荷並封裝到ICMP中。爲何要用8000,是由於SRX01的本地鏈路MTU最大值爲9000字節(包含IP包頭+ICMP包頭),因此我須要隨機選擇一個比9000稍小的數。
在上面測試中,當我用8k字節ping一個數據包的時候,ping測試失敗。從而證實中間鏈路的MTU值是小於8000字節的。
同時,在Ping 2.2.2.2 的過程當中,SRX01收到一個錯誤信息。
36 bytes from 1.1.1.100: frag neededand DF set (MTU 1500)
有一條從1.1.1.100發過來的消息,內容大體以下:
你的數據包太大。要想往前走,數據包須要分片,但是DF=1,我無法給你分。(順便悄悄告訴你,前方MTU值爲1500。)
難道ISP運營商內部還有咱的人,還給透露小道消息,在這裏先無論這高人是誰,後續聊到Path MTU Discovery時,將經過抓包揭曉謎底。
咱們就只須要知道有高人指點,前方ISO網絡層數據包MTU大小最大爲1500字節。
抱着半信半疑的態度,咱們再Ping測試一次。
可是在開始測試以前,先打一個小算盤:
網絡層1500字節=20字節IP頭+8字節ICMP頭+1472字節的載荷。
按照上面的推理,我猜若是Ping數據包載荷size=1472字節的話,就會成功。而若是稍稍多一點,例如1473字節Ping就會失敗。
經過實驗證實:
Ping Size=1472字節的包:
lab@SRX01>ping 2.2.2.2 source 1.1.1.1 rapid count 1 do-not-fragment size 1472 PING2.2.2.2 (2.2.2.2): 1472 data bytes ! --- 2.2.2.2ping statistics --- 1 packets transmitted, 1 packets received, 0% packet loss round-tripmin/avg/max/stddev = 28.471/28.471/28.471/0.000 ms
Ping Size=1473字節的包:
lab@SRX01>ping 2.2.2.2 source 1.1.1.1 rapid count 1 do-not-fragment size 1473 PING2.2.2.2 (2.2.2.2): 1473 data bytes 36 bytesfrom 1.1.1.100: frag needed and DF set (MTU 1500) Vr HLTOS Len ID Flg off TTL Pro cks Src Dst 4 5 00 05dd d60b 2 0000 40 01 590f 1.1.1.1 2.2.2.2 . --- 2.2.2.2ping statistics --- 1 packets transmitted, 0 packets received, 100% packet loss
驗證成功。咱們如今能夠100%肯定,此神祕人物透露的1500字節的MTU值是絕對可信的。同時也獲悉端到端鏈路ISO第三層的最佳MTU值爲1500字節。
以上就是手工測試法,簡單明瞭。
可是有一個問題?
做爲管理員,咱們經過測試明確了端到端MTU的實際值。但是咱們如何也讓網絡中的應用程序也知曉這1500字節的MTU值呢?
讓咱們繼續往下走。
TCP-MSS,全稱TCP maximum segment size。翻譯過來是TCP最大報文尺寸。它的值表明TCP傳輸層指望對端發送給本身單個TCP報文的最大尺寸。
通俗來講,當TCP協議兩端在初始協商進行TCP三次握手協議的時候,主機兩端會把本身當前所在鏈路的MSS值告知對方。當一端主機收到另一端的MSS值候,它會評估其MSS值並與本身的MSS值作對比,取最小的值來決定TCP發送的最大報文尺寸。
如何計算本地MSS值?
本地MSS=MTU-20字節的標準IP頭-20字節的標準TCP頭(換個角度看其實就是TCP負載)
那TCP-MSS如何在避免數據包分片中,發揮它的做用呢?
讓咱們來看一個實際示例:
還記得在測試環境中介紹的兩臺服務器Server 7 和Server 8嗎?
如今兩臺服務器要搞事情了。
如上圖,服務器Server 7 要往Server 8 用SCP的方式傳送一個40M的文件。Server7 的MTU 爲9000字節,Server8 的MTU 2000 字節。
TCP行爲理論分析:
在TCP協商期間,Server 7和Server 8之間會把本身當前的MSS值告知對方,經過對比本地MSS與對方的MSS值後,取二者最小值,以下:
Server 7MSS值爲9000-40=8960字節。
Server 8 MSS值爲2000-40=1960字節。
很明顯,Server 7和Server8 會達成協議,二者中取Server 8的MSS值,即1960字節。這個值將是他們的TCP數據傳輸過程當中單個TCP數據包載荷的最大值。
讓咱們經過實驗抓包來驗證理論分析:
如上圖,正如理論分析。在Server 7(3.3.3.3)與Server8(4.4.4.4)TCP三次握手期間,Server7發送了8960字節的MSS,而Server8發送了1960字節的MSS。
爲了證實Server7 選擇了較低的1960字節的MSS,讓咱們看看數據包傳輸過程當中的TCP數據包大小。
由於TCP存在窗口流控機制,TCP速率不會從一開始就達到最大值,而是一個按部就班增加的過程,固然最後仍是如上圖紅框所示達到了TCP的單包最大值2014字節,即TCP-MSS值。
這裏的2014爲整個數據包大小,分拆後以下:
2014字節=14字節二層幀頭+20字節IP頭+20字節標準TCP頭+12字節TCP可選項+1948的負載。
此處的TCP-MSS仍然爲1960字節,只是被拆分紅爲了12字節的TCP可選項+1948的負載。
(記住MSS計算是以標準的20 字節TCP頭爲參考,在計算時拖掛的TCP選項被放在負載以內考慮)
經過抓包證實,Server7 的確使用了Server 8彙報的1960字節的TCP-MSS爲最大報文尺寸,而不是自身的8960字節。從而證實咱們的理論分析徹底正確。
可是,讓咱們換個視角看看這些數據包在運營商網絡裏面是什麼樣:
上圖爲運營商路由器SRX03 的ge-0/0/0接口抓包,你們是否已經看見了每一個數據包都帶了一個分片包的尾巴,以及大量刺眼的TCP Ack數據包。
一個完整的2014字節數據包就這樣被一分爲二:1514字節數據包+534字節數據包
那爲何數據包在運營商網絡會被分片?
你們是否還記得。在第一步中,咱們經過人工方式知曉了運營商網絡的ISO第三層網絡層MTU值爲1500字節。因此很明顯,2014字節的數據包超過了1514(1500網絡層+14字節鏈路層二層幀頭)的大小,從而數據包被切割分片。
解決方案:攔截TCP-MSS值
因爲管理員經過手工測試獲悉了整條鏈路的TCP-MSS值。若是咱們可以配置站點A或B的SRX路由器,攔截並修改Server7 和Server8之間的TCP-MSS協商爲手工測試的TCP-MSS值,變相告知兩臺服務器正確的端到端TCP-MSS。那豈不避免了服務器上的TCP應用不至於觸及到運營商網絡的MTU天花板,從而避免被分片的命運?
答案是Yes!
在SRX01以及SRX02做以下配置:
set security flow tcp-mss all-tcp mss 1460
完成配置之後,在站點A的SRX01面向運營商接口的ge-0/0/1抓包以下:
如上圖,當Server 7和Server8 在協商TCP-MSS時,不管是Server7 或Server8發送的TCP-MSS均爲1460字節。
同時,經過查看TCP數據流,咱們能夠很明顯的看出修改先後的區別,在上圖中TCP完成窗口初始化後,直接以1514字節的整包傳輸,而不是先嚐試2014字節。
TCP-MSS實驗小結:
· 經過修改TCP-MSS的確可以有效的防止TCP流量觸及天花板,進而優化TCP的傳輸性能。
· 可是TCP-MSS有一個弊端,那就是須要人工先提早檢測出整個鏈路的MTU值,並在出口路由器上全局干預站點的TCP-MSS協商。
你說要是這MTU可以自動發現,徹底不須要人爲干預多好啊!
方法是有的,請接着看。
Path MTUDiscovery,MTU自動發現!
這工具一聽就以爲高大上,可是做爲資深網工,咱們不光要知道 Path MTU Discovery(如下簡稱PMTU)是什麼,更須要清楚PMTU是如何高大上,並自動發現MTU最優值的?
先上理論:
顧名思義,PMTU自動發現就是賦予應用程序權力讓其自主發現端到端鏈路的MTU值,並繞開數據包分片這個坑。
目前支持PMTU的協議爲TCP以及UDP。
其MTU發現機制很是巧妙和簡單,用一句話形容就是:不怕犯錯勇於嘗試,最後總會得出正確值。
方法以下:
當主機發送TCP/UDP數據包時,主機會在每個發送的數據包上打上DF=1的標誌,當這些數據包通過下游鏈路到達目的地以前,因爲DF1的緣由數據包永遠不會被中間節點分片。
天然而然,數據包的結局只可能有兩種:被中間路由器丟棄或者順利到達目的地。
同時,主機在發送數據包給下游目的地時,它並不知曉整個網絡鏈路上的最小MTU值。介於此,主機在初期發送數據包時,數據包尺寸爲其所在鏈路的MTU值。
把上面兩個條件組合起來後,主機發送的數據包就會出現以下結局:
1. 若是主機本地鏈路的MTU大於端到端鏈路中某一點的MTU值,那麼這個數據包由於有DF=1的緣由,會被丟棄。
2. 若是路由器本地鏈路的MTU爲整個端到端鏈路中最小值時,數據包很幸運的被送達目的地。
對於結局2,皆大歡喜。
而咱們須要重點說說結局1。在結局1中,當鏈路中路由器丟棄此數據包時,此路由器會返回一個ICMP 的Destination Unreachable,Fragment Needed(目標不可達,須要分片)的消息給源主機。
對源主機而言,相比知曉目標不可達而言。它更須要另一個消息:
這個ICMP包中另有玄機,它同時也包含了此鏈路路由器的下一跳MTU值!
回到本文章第一步手工測試MTU那一段,我曾提到了一個運營商內部人士,他悄悄告知了咱們ISP運營商正確的MTU值是多少。而這個高人正是丟包路由器的ICMP 目標不可達消息。咱們能夠把這個ICMP數據包理解爲一個信使,經過告知源主機正確MTU值後,源主機能夠調節字節的發送數據包尺寸,從而避免數據過大被丟棄。
演示案例:
仍是以TCP-MSS中的Server7和Server8通訊爲例,服務器Server 7 要往Server 8 用SCP的方式傳送一個40M的文件。Server7 MTU9000字節,Server8 MTU 2000 字節。
不過與TCP-MSS狀況不一樣,在此案例中咱們在Server7和Server8上開啓了PMTU。
同時關閉站點A與B出口路由器SRX01 和SRX02的TCP-MSS攔截:
lab@SRX01#delete security flow tcp-mss [edit] lab@SRX01#show | compare [editsecurity] - flow { - tcp-mss { - all-tcp { - mss 1460; - } - } - }
經過上圖,Server7 和Server8恢復到了8960字節和1960字節的TCP-MSS。
重點在下圖:
你們能夠看見,根據TCP-MSS協商原則,Server7最終選擇了較低的2014字節,可是這個值仍是大於了運營商鏈路中的MTU=1514。
正如以前所說,IP爲1.1.1.100(ISP運營商SRX03)的路由器針對每個丟棄的數據包回覆了一個ICMP不可達消息。而更有意思的是,在這個ICMP包裏面攜帶了下一跳MTU=1500的驚天大祕密。
而做爲源的Server7也不簡單,當它收到這個小道消息後,立刻修改了本身的數據包發送尺寸。從2014當即改成1514(底部紅色字體數據包串),並使用此尺寸來發送後續的TCP重傳數據包。
PMTU小結:
以上就是一個典型的PMTU行爲案例。從中能夠看出,PMTU不須要人爲干預其具體MTU值,PMTU會經過試錯的方式來發現最佳MTU值。
固然鏈路中可能存在各式各樣的MTU值,而PMTU則以不變應萬變。只要把上述過程在不一樣鏈路中重複一次或屢次就必定會最終發現一個端到端的最優MTU值。
那PMTU有什麼缺陷?
你或許已經猜到了,它太依賴ICMP消息。
在Path MTU Discovery中,咱們發現PMTU工做的核心機制在於主機可以收到中間某個節點發過來的ICMP不可達數據包,幷包含了下一跳MTU值。
那假設咱們在上述拓撲中,把站點A的SRX01入站口放置ACL阻止ICMP從運營商進入站點A。
雖然理論上給站點A帶來了額外的安全保障,可是反作用就是PMTU被幹掉了。
由於缺失ICMP消息,PMTU再也不生效。
解決方法:
平常工做中,你們能夠考慮在邊界防火牆上放行ICMP協議,或者至少放行ICMP unreachable(ICMP Type 3 Code 4)消息。
在通常網絡拓撲環境中,每每在三層路由器設備之間會經過二層交換機匯聚互聯。
可是在某些狀況下,由於設計緣由或者人爲失誤。致使二層交換機的MTU值小於三層路由器MTU值,從而致使網絡故障。
可能有人會問,那MTU小了,分片就能夠了,也不至於產生網絡故障。
可是仔細考慮發現,數據包分片只存在於ISO第三層的網絡設備上,而二層節點只查看二層幀,其並無重寫三層IP頭的能力,更不知曉三層IP層的具體網絡細節。
當數據包過大之後,二層設備是不會也不能去分片數據包,由於在配置的時候,沒有賦予它任何此二層VLAN的IP信息,致使其沒有寫IP數據包的能力去執行數據包分片。
讓咱們來看一個詭異的示例:
如上圖,SRX3和SRX5之間配置了9000字節的MTU,而SRX03和SRX05則經過SRX04的二層設備互聯。
在二層SRX04設備上,全部ISO二層幀MTU值爲1514。
因爲SRX03和SRX05是ISP運營商路由器,它們之間運行了BGP路由協議。可是令網絡工程師不解的是,SRX03和SRX05的BGP鄰居雖然處在UP狀態。可是SRX05沒有收到任何SRX03通告的路由?
SRX03 BGP鄰居信息:
root@SRX3> show bgp summary Groups: 2 Peers: 2 Down peers: 0 Table TotPaths Act Paths Suppressed History Damp State Pending inet.0 10 7 0 0 0 0 Peer AS InPkt OutPkt OutQ Flaps Last Up/DwnState|#Active/Received/Accepted/Damped... 1.1.1.1 101 13 19 0 3 3:53 3/4/4/0 0/0/0/0 35.0.0.5 200 5 34 6904 7 11 4/6/6/0 0/0/0/0
#上述輸出中,SRX05的35.0.0.5在SRX03的鄰居列表中,而且SRX03收到了SRX05宣告的6條路由。以下:
root@SRX3> show route receive-protocol bgp 35.0.0.5 inet.0: 10009 destinations, 10013 routes (10009 active, 0holddown, 0 hidden) Prefix Nexthop MED Lclpref AS path * 2.2.2.0/24 35.0.0.5 200 I * 4.4.4.0/24 35.0.0.5 200 201 I * 10.69.109.0/24 35.0.0.5 200 I 10.221.22.0/24 35.0.0.5 200 201 I 35.0.0.0/24 35.0.0.5 200 I * 172.16.1.0/24 35.0.0.5 200 201 I root@SRX3>
可是在SRX05中,卻沒有收到任何SRX03的路由條目:
root@SRX5> show bgp summary Groups: 2 Peers: 2 Down peers: 0 Table TotPaths Act Paths Suppressed History Damp State Pending inet.0 4 3 0 0 0 0 Peer AS InPkt OutPkt OutQ Flaps Last Up/DwnState|#Active/Received/Accepted/Damped... 2.2.2.2 201 36075 35936 0 3 1w4d6h 3/4/4/0 0/0/0/0 35.0.0.3 100 2 5 0 8 4 0/0/0/0 0/0/0/0
更詭異的是,二者的BGP鄰居老是過一段時間後就閃斷一次。
讓咱們來經過抓包來揭示謎底:
在二層設備SRX04上抓包以下:
很明顯,當SRX03(35.0.0.3)與SRX05(35.0.0.5)經過TCP創建BGP鄰居時一切正常。數據包大小均不大於1500字節。
可是當BGP開始經過Update消息傳輸路由條目(NLRI)的時候,開始以單包8000字節大小以上數據包傳輸。而中間的SRX04 ISO二層MTU爲1514字節(三層MTU爲1500字節),這8000字節的數據包將會被無情的丟棄。而由於SRX04是二層設備,其將不會返回任何ICMP信息給SRX03。形成SRX03的TCP數據包不斷超時並重傳。最終在到達TCP最大重傳次數後,BGP鄰居被刪除。
解決方法:
請務必保證路由器之間的二層設備MTU值與三層路由器設備MTU相同。
在這片文章中,咱們一塊兒分析了常見MTU最優值的發現方法,並簡單列舉了兩個常見MTU問題,知識回顧以下:
1. 手工MTU發現:經過手工ICMPPing測試發現最優MTU值。
2. TCP-MSS:TCP協議的最大傳輸報文尺寸,經過在中間防火牆或者路由器干預端到端的TCP-MSS協商從而達到避免鏈路數據包分片的目的。
3. Path MTU Discovery:用於TCP/UDP數據包,經過設置初始數據包的DF=1不斷試探最佳MTU值,最終發現端到端的最佳MTU值。
固然,在平常工做中,MTU的問題會比咱們想象的更爲複雜。
例如嵌套了IPsec ***和GRE隧道的端到端流量等。可是萬變不離其中,只要你們掌握了MTU和相關工具的工做原理和細節。咱們就能夠從容分析各類場景並使用對應的工具來解決實際問題。
謝謝!