正則安安每晚每隔三小時必然哭鬧,我索性也就不睡了,,反正也睡不好,,起來泡茶,喝酒,,作文,。 浙江溫州皮鞋?濕,下雨??進水不會胖,! 杭州,,外面依然是寒雨夜,屋里也沒開空調,,我穿個夏天的短袖,,旁邊放一杯熱茶,喝完了還有昨晚實在喝不下去的漢拿山燒酒,,再喝完還有上周菜市場買的米酒…作此文一篇,。 在我們check IPv6的基本特征列表時,總是可以看到IPv6對Anycast的支持,。說實話,,對于很多人而言,,這是個比較陌生的概念,對于希望看看Anycast到底是什么樣子的人而言,,甚至在網上很難搜到關于 如何配置Anycast 的資源,。這是比較令人遺憾的。 拋開概念,,那么本文嘗試從不同的角度來針對Anycast探究一番,。 IPv4年代的Anycast說起Anycast,并不是在IPv6標準中突然出現的概念,,一個概念怎么可能突然出現,?不可能的。 早在很久很久以前,,業(yè)界就針對IPv4提出了Anycast的說法,,只不過相對而言,IPv6在操作上將其標準化了而已,,如果說IPv4年代的Anycast標準只是 建議 ,,那么IPv6的Anycast就是規(guī)定了些許 MUST , MAY,。 建議閱讀: 那么,,到底如何理解Anycast? 本質上,, Anycast就是將同一個IP地址配置在不同的主機網卡上,,然后利用各種選路機制欺騙源主機的一種通信方式。 什么,?同一個IP地址配置在不同的主機上,,這不是地址沖突了嗎?我們記得在初學網絡基礎的時候,,教程上就講過 IP地址不能沖突,! 現在為什么IP沖突變成了一種通信方式了呢?真是只許州官放火,,不許百姓點燈?。?/p> 其實不然,,我倒是覺得Anycast是內功深到一定程度,,自然而然的一個想法。我們簡單地從路由說起,。 我們知道,,IP地址存在的目的就是為了指揮路由器選路,最終將數據包路由到目的地,,那么IP地址沖突的結果是什么,? IP地址沖突不是問題,,路由沖突才是!,! 比如路由器R上配置的下面的兩條路由:
請問一個去往目的地1.1.1.1的數據包到達路由器R之后到底是從e2走呢,還是從e3走呢,?這就是問題,。但是同樣的路由,加一個約束就不會有問題:
路由器會毫不猶豫地將去往1.1.1.1的數據包從e3發(fā)出,! 對于上述的兩條路由,,你說是IP地址沖突嗎?不,!并不是,。 互聯網本身就是一個互相網狀連通的連通圖,到達同一個目的地的路徑不止一條,,對于路由器R而言,,它只管選路,逐跳轉發(fā)數據包,,它并不關注1.1.1.1這個目標地址到底在哪里,。 好了,現在我們知道只要路由不沖突,,就沒有問題,,數據包總是可以特定的路徑,逐跳被轉發(fā),,最終到達目的地?,F在,我們看一下這條路是如何形成的,,或者說路由器R是怎么知道到達1.1.1.1有兩條路可走的。 由于這只是一篇散文,,并不是技術文檔,,所以我并不想引入BGP,AS這些概念,,姑且把全球的互聯網看作是一張如下圖所示的連通圖: 就這樣,,子網信息,,路由信息在整張網上彼此交換,傳播,,最終在每一臺路由器上形成了穩(wěn)定的路由表:
如果說在這張網中有A和C需要訪問1.1.1.1,,那么很顯然,,路徑如下: 這會造成路由器R1和路由器P之間的鏈路異常擁堵,,為什么R0不能分擔一部分流量呢,? 嗯,我能想到的,,TCP/IP標準化協會的那幫人難道能想不到,?這就是ECMP的由來。再后來,,干脆來個SDN全局統一分發(fā)好了…但是這和Anycast沒有半毛錢的關系,,所以就此打住,我們來看看另外一種引出Anycast的解法,。 試想,, 如果B節(jié)點也通告1.1.1.0/24的路由會怎樣? 按照前面的路子,我們知道,,B和P均通告相同的路由,,這會造成圖上所有路由器均會收到來自B和P關于1.1.1.0/24的通告,按照上面的兩個基本原則:
你猜怎么著,?最終成了下面的樣子了: 是不是很像在世界互聯網上部署了一個天然的負載均衡設施?。∈堑?!這就是所有的 IP地址沖突導致的結果,! 這就是 Anycast 。 其精髓就是: 在路由器看來,,它們并不知道不同指向的下一跳最終將數據包導向不同的目的地,,它們只是認為這只是通往同一個目的地的不同路徑罷了! 簡單點說,, Anycast之所以得以部署和實現,,就是利用了IP協議逐跳尋址的特性! 事實上,,Anycast的結果是,,相同的IP地址位于不同的主機,因此,,它的弊端也是顯而易見的,。 由于 逐跳的路由收斂 和 端到端的五元組連接 之間并沒有同步,因此Anycast并不適合基于端到端連接的TCP應用,。 TCP并沒有廣域范圍的連接遷移機制,,因此如果路由重新收斂,將會導致連接斷開,!比如上述的例子,,如果A到B之間的線路擁塞或者說斷開,那么路由會重新收斂到A-R-R1-P這條路徑,,A和B的1.1.1.0/24子網的主機之間的TCP連接將會斷開,,這并不是人們所期望的。 因此,,上述描述中的Anycast只適合于一來一回兩個包的oneshot式的交互通信,比如DNS,! 是的,,DNS就是這么部署的,比如我們經常使用的Google DNS 8.8.8.8,它實際上就是Anycast部署在世界不同地方的多臺主機,,地址全部都是8.8.8.8,! 請使勁閱讀:https://developers.google.com/speed/public-dns/faq 然后去深擼這個站點,溯源:https://bgp. 至此,,我覺得關于Anycast的概念,,已經大致陳述清楚了。 下面是IPv6的世界,。我們跟蹤問題本身以及其解法,,跟著RFC來梳理IPv6 Anycast的來龍去脈,其實一切都很清晰,。 IPv6的Anycast重看Anycast在IPv4上的問題,,我們知道, 把同一個IP地址配置在不同的主機上,,這確實是不妥的,,比如占據互聯網流量頭把交椅的TCP應用就不適合, 既然無法讓主子心安理得的承認,,那索性在Anycast標準化中就不要這么做就是了,。 但是,只要Anycast不是部署在端節(jié)點,,而是部署在路徑節(jié)點,,比如路由器上,那就是妥妥的,。逐跳尋址原則最終導致Anycast部署在路由器上之后,,會自然而然地實現ECMP,即多條路徑分擔同樣的端到端通信,。 在繼續(xù)下去之前,,這里先說一個觀點。那就是 端到端通信多路分擔這種機制對TCP是不好的,!
好了,,我們先不管TCP了,,任它腐爛吧! IPv6對Anycast進行了標準化,,首先在RFC3513中,,它對Anycast提出了兩點約束:
有了這兩點約束,我們可以知道: 在IPv6中,,Anycast不是用來通信的,,而是用來尋址的。 緊接著,,RFC3513要求 所有的路由器的所有接口 都必須配置一個 必選的Anycast地址:
比方說,,路由R有兩個接口,分別配置了兩個IP地址:
那么根據RFC的要求,,這個路由器上將會生成下面的Anycast地址:
為了使得這些Anycast能被訪問到,,需要添加兩條本地主機路由:
這里需要解釋一點,剛才不是說IPv6的Anycast不是用來通信的嗎,?那 為什么還要被訪問呢,? 因為需要鄰居解析(IPv6 Ndp)。如果有誰把這個地址設置為下一跳了,,那么需要解析這個地址,,這就是 被訪問! 納尼,?Anycast作為下一跳,? 是的,,這就是IPv6 Anycast的核心用法,它不是用來標識主機服務讓你的應用程序通信,,它是用來尋址的:
來吧,我們還是舉例子的好,。 我的局域網為了備份,,希望部署兩臺或者多臺路由器做熱備,姑且就先兩臺吧: 假設兩臺路由器都能接外網,,如果跑IPv4協議,,那么自然而然的想法就是安裝keepalived跑VRRP,這種成熟的東西,,想必都可以瞬間完成配置,。 但是,我們知道,,這兩臺路由器只有一臺是工作狀態(tài),,另外一臺處于backup standby,是不是感覺浪費了資源,?如果你想讓它們一起工作,,那就要:
萬萬不能配置成相同的IPv4地址的,因為這種地址沖突會導致交換機的轉發(fā)表以及ARP表的混亂,。當然,,對于我個人而言,我是有辦法將其配置成相同的IP地址又不會confuse各種表的,,但是,,配置太復雜了(涉及iptables,ebtables,,arptables,,arp,iproute2,,STP等等),。正如IPv4的Anycast一樣,沒有什么是IPv4配置不出來的,,只是這些大部分都是奇技淫巧般的Trick,!玩物喪志,! 我們看一下用IPv6會怎樣。 不用干別的,,如果路由器的實現遵循RFC標準,,那么你只需要配置兩臺路由器不同的同網段地址即可,如下:
然后所有主機的默認網關設置成其Anycast地址即可:
就這么簡單,!Why,? 因為路由器1和路由器2在配置好內網e0的地址后,根據RFC3513,,它們會自動生成Anycast地址以及Anycast地址的主機路由以被內網主機鄰居解析,。 RFC要求各層尋址Anycast地址時以 本層次的路由距離 來度量,那么對于二層鏈路,,其距離默認就是物理距離,,光速不變,距離等效于時間,,因此會等效為 誰先回復我的鄰居請求,,誰就是我要尋址的Anycast節(jié)點! 現在有個不可回避的問題需要解決,那就是 訪問互聯網服務的正向包和返回包路徑不對稱問題,。 比如,,h1主機訪問服務器S走的R1作為默認網關,然而S返回h1時,,卻從R2返回,,此時R2解析h1的地址,h1收到R2的解析請求后,,會不會更新自己關于Anycast鄰居的信息呢,?如果是的話,那勢必會造成鄰居表信息的劇烈抖動??! 答案是 并不會! Why,? 因為IPv6在解析鄰居時,,ICMPv6協議頭里會寫清楚下面的信息:
這一點和IPv4的ARP不同,ARP是雙向更新的,,在回復自己的MAC地址時,,同時也更新了自己的ARP表,但在IPv6中,,兩者分開了:
R2發(fā)送給h1的鄰居請求,,只是請求h1的MAC地址而已,,并沒有說要h1更新其鄰居信息,所以萬事大吉: 配置和實現現在該看看實現了,。 很少有資料講 如何在Linux上配置IPv6的Anycast 的,,這一次可能我又占了坑。 其實很簡單,,只要開啟IPv6的轉發(fā)即可:
這個時候,,你就會在/proc/net/anycast6看到內容:
我在enp0s9上配置了如下的IPv6地址:
所以說,什么都不用干,,Linux內核自動幫我生成了其對應的Anycast地址,對應RFC3513的2.6.1 Required Anycast Address格式:240e:918:8003:: 按照上面一個小節(jié)最后的例子,,我們知道,,這個 240e:918:8003:: 是可以被鄰居發(fā)現而解析的,而我們知道,,IPv6的鄰居發(fā)現使用的是組播地址,,其組播構成規(guī)則詳見: 對應組播地址:
我們針對Linux的如上配置確認一下:
將Anycast地址作為默認網關發(fā)送數據,,最終鄰居解析的時候,,只要發(fā)送到組播地址 ff02::1:FF00:: 就可以解析出該網段上的Anycast地址的MAC地址信息,然后 取第一個到達的作為鄰居 即可,! 上面關于組播的設置,,請看 addrconf_join_anycast 函數:
其中,ipv6_dev_ac_inc 值得觀摩,! 配置也配好了,,那么我們找兩臺機器練一練手吧。 這次我部署的另外一個機器是Windows 7系統,,順便玩一下netsh,。這臺Win7系統機器和我們的Linux Rh7.2直連,拓撲我就不畫了,,非常簡單,。我只是把Win7上的地址配置發(fā)布出來。 很簡單,,Win7上配置一個 240e:918:8003::/64* 同網段的IPv6地址: 這個時候,,將Win7的默認網關設置成 240e:918:8003::* 這個Linux上使能的Anycast地址,看看如何通信,。 按照慣例,,ping一下這個 240e:918:8003::* 地址: 在Linux上抓包,,發(fā)現是有回復ICMPv6 Echo Reply的,,只是說回復的源IP地址不是Win7期望的Anycast地址,,而是Linux上enp0s9網卡的地址,這正是印證了 An anycast address must not be used as the source address of an IPv6 packet. 這句話,! 我很好奇Linux內核是怎么做到 不讓Anycast地址作為源地址的 ,,ping不行,TCP的Telnet也不行…其實看一下代碼就完全明白了,。 先看下Telnet為什么完全就沒有SYN-ACK回復: 脈絡理清了之后,,我們來反一下,,讓Win7主機配置Anycast。 我特意沒有按照RFC的規(guī)定,,去配置了一個非標準的Required Anycast Address,,且看: 我并沒有讓低n-bit為全0,竟然成功了,,這說明Win7并沒有嚴格按照RFC的規(guī)范行事,,它完全是手動的。 那么好,,我在Linux上去ping這個Win7的Anycast地址: 得到了Win7的回復,,然而源地址不是Win7的Anycast地址,卻是Win7的物理網卡 本地連接 3 上配置的IPv6地址,。這依然印證了 An anycast address must not be used as the source address of an IPv6 packet. 這句話,。 只是說,Win7對Anycast地址 并沒有嚴格遵循subnet后面的低bits均為0的約束 ,,即Win7沒有實現 嚴格的Required Anycast Address,! 不管怎么樣,痛則不通,,通則不痛,,后面也沒啥可玩的了。 總結IPv6的Anycast:
因為我們可以將Anycast總結為:
此外,,RFC2526又規(guī)定了 保留的Anycast地址 用于不同的目的: 閱讀筆記為了寫這篇文章,我深夜快速瀏覽了RFC標準,,因為我要在這些個標準之上才能胡扯形而上吧,。 這兩個截圖體現了IPv6 Anycast的作用,它到底用在哪?我想我在上文呢,,已經闡述清楚了,。 后記為Anycast添加一條host路由,讓anycast地址可以被設置成網關,。 昨晚睡的有點早,,這周末又要去公司附近拉一車行李,有點忙,。白天基本沒空,,所以就以安安吃奶鬧鈴為由,作文一篇,。 浙江溫州皮鞋濕,,下雨進水不會胖。 |
|
來自: supercodec > 《網絡技術》