閒談IPv6-沒有選項勝有選項的TLV
皮鞋溼了,只要是溫州的,雖溼而不胖。
IPv6協議頭固定,並且非常簡單,去掉了IPv6的選項欄位,把變長頭部統改成了定長。這有什麼益處就不多說了,肯定百分百地是提升了處理效率。然而,這裡我要說的是,在獲得這些收益的同時,其實並沒有付出任何代價!
這也就是說,IPv4的設計在某種意義上是錯誤的設計!不過呢,也不必因為我這句話而大跌眼鏡,進化嘛,缺陷總是有的。
我們乍看IPv6,好像是缺失了options選項,這是不是意味著它和IPv4相比,功能弱化了很多呢?非也!
相反,IPv6強化了很多。看似矛盾的兩個IP版本,其實並不矛盾!
IPv6並不是簡單地說一句 “不支援選項了” ,它的意思實際上是在說, “IPv6可以無限支援選項!” 它之所以把IP選項從IP頭裡面剝離開來,其實是想更好地去處理選項,不然,最多40位元組的選項實在是太雞肋了,脫離IP頭部而自立門戶顯然是一個更好的選擇。
鏈式協議頭
為了處理這些少到無,多到無窮盡的 選項 ,IPv6採用了鏈式處理。如果可能,則將每一個選項邏輯都單列為一個 上層協議 ,以next header來標識,這便為IPv6的擴充套件提供了無限的可能。比如下面的鏈式處理:

我們看一下IPv4的情況:

TLV結構
也許是我接觸TLV之前沒有接觸過其它什麼其它的表示型語法,但我就是喜歡TLV,相反,我討厭json,XML,HTML這些。
我並不怎麼懂程式設計,也不懂什麼程式語言,加上我感興趣的最初的網路協議也都不是用於表示內容的,而是僅僅規定格式的,所以,我第一次接觸TLV是很晚了,大概是在2010年左右,我當時在做X.509證書的相關工作,涉及到ASN.1編碼。
第一次接觸TLV,我感覺這太棒了!它像是一個俄羅斯套娃,竟然可以上下無限擴充套件,使我可以開心顏!簡直太棒了!
說了這麼多,其實我想說,IPv6的諸多options擴充套件頭,都是採用了TLV的編碼格式。
我們看看 HAO擴充套件 ,大概就是Home Address Option的縮寫,它其實就是一個IPv6地址,代表在移動IP中的 家鄉IPv6地址 的概念。它就是一個TLV結構表示的結構體:
/* *home address option in destination options header */ struct ipv6_destopt_hao { __u8type; __u8length; struct in6_addraddr; } __attribute__((packed));
它被封裝在了一個叫做ipv6_destopt_hdr的擴充套件頭裡:
struct ipv6_opt_hdr { __u8nexthdr; __u8hdrlen; /* * TLV encoded option data follows. */ } __attribute__((packed));/* required for some archs */ #define ipv6_destopt_hdr ipv6_opt_hdr
在IPv6裡,ipv6_destopt_hdr這個擴充套件選項頭的協議號(***記住,在IP看來,它是一個“上層協議”***)是60:
#define IPPROTO_DSTOPTS60/* IPv6 destination options */
因此,假設一個節點的Home地址是240e:111::123,其轉交地址care-of為2007:111::123,那麼它發往2009:111::123的TCP封包就應該是:

hop-by-hop 與TLV
事實上,你可以在任何支援TLV的擴充套件頭裡去拼裝任何的TLV,關於該TLV的解釋,你只需要自行實現一個回撥函式即可。
這裡要提到的就是 逐跳頭 。
IPv6的逐跳頭,意思是說, 每一個經由的路由器都要去解析這個頭部所包含的每一個選項。 這個是協議層面的實現決定的,如果你的實現中沒有顯式解析這個頭部的選項,那就意味著你沒有完備實現IPv6協議,看起來很死板,不是嗎?但是逐跳頭對其包含的選項的解釋確實靈活多變的。
逐跳頭包含一系列的TLV選項,一個或者多個。每一個TLV選項都有一個特定的處理方式, 包括但不限於:
- 直接處理,更新協議棧資料結構。
- 將資料交由應用層去處理
無論如何,協議棧必須對逐跳頭有所反應,也就是說,如果這個逐跳頭是錯誤的,有問題的,那麼就必須要返回錯誤。
你想特殊處理逐跳頭嗎?
你想新增新的逐跳選項麼?簡單註冊一個TLV處理函式即可!
我們來看一下Linux核心是如何處理逐跳頭的,首先在ipv6_rcv中,顯式處理逐跳頭:
if (hdr->nexthdr == NEXTHDR_HOP) { if (ipv6_parse_hopopts(skb) < 0) { IP6_INC_STATS_BH(net, idev, IPSTATS_MIB_INHDRERRORS); rcu_read_unlock(); return NET_RX_DROP; } }
這就是顯式呼叫。
其中ipv6_parse_hopopts完成了一切。在該函式中,內部呼叫ip6_parse_tlv函式:
在一個迴圈解析中,呼叫可能的func回撥函式!
反正就是說,只要資料包到達,並且其中有逐跳頭,那你就必須去處理它,至於說怎麼處理,標準就不管了。雖然標準不管,我們還是可以理解一個應用,那就是資源預留,即RSVP執行的場景。
年華如沙在指隙間悄然流逝,點點散落在未明的塵世。看不透的世事,道不明的情愁,緣夢戀塵盡成灰,浮華如斯東逝水。
浙江溫州皮鞋溼,下雨進水不會胖。