皮鞋湿了,只要是温州的,虽湿而不胖。
IPv6协议头固定,并且非常简单,去掉了IPv6的选项字段,把变长头部统改成了定长。这有什么益处就不多说了,肯定百分百地是提升了处理效率。然而,这里我要说的是,在获得这些收益的同时,其实并没有付出任何代价!
这也就是说,IPv4的设计在某种意义上是错误的设计!不过呢,也不必因为我这句话而大跌眼镜,进化嘛,缺陷总是有的。
我们乍看IPv6,好像是缺失了options选项,这是不是意味着它和IPv4相比,功能弱化了很多呢?非也!
相反,IPv6强化了很多。看似矛盾的两个IP版本,其实并不矛盾!
IPv6并不是简单地说一句 “不支持选项了” ,它的意思实际上是在说, “IPv6可以无限支持选项!” 它之所以把IP选项从IP头里面剥离开来,其实是想更好地去处理选项,不然,最多40字节的选项实在是太鸡肋了,脱离IP头部而自立门户显然是一个更好的选择。
为了处理这些少到无,多到无穷尽的 选项 ,IPv6采用了链式处理。如果可能,则将每一个选项逻辑都单列为一个 上层协议 ,以next header来标识,这便为IPv6的扩展提供了无限的可能。比如下面的链式处理:
也许是我接触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 {
__u8 type;
__u8 length;
struct in6_addr addr;
} __attribute__((packed));
它被封装在了一个叫做ipv6_destopt_hdr的扩展头里:
struct ipv6_opt_hdr {
__u8 nexthdr;
__u8 hdrlen;
/*
* 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_DSTOPTS 60 /* IPv6 destination options */
因此,假设一个节点的Home地址是240e:111::123,其转交地址care-of为2007:111::123,那么它发往2009:111::123的TCP封包就应该是:
事实上,你可以在任何支持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运行的场景。
年华如沙在指隙间悄然流逝,点点散落在未明的尘世。看不透的世事,道不明的情愁,缘梦恋尘尽成灰,浮华如斯东逝水。
浙江温州皮鞋湿,下雨进水不会胖。