分类: BSD
2012-03-04 11:56:14
每一个Ipv6地址都属于且只属于一个对应于其地址范围的区域。例如,可聚合的全球单播地址(Aggregatable Global Unicast Addresses)地址范围就是全球;链路本地地址(Link-Local Addresses)的地址范围就是由一条特定的网络链路和连接到这条链路的多个接口组成的区域。
这样,地址的唯一性只能在其范围区域内的到保证。因此,范围受限地址在其范围区域边界上就具有了二义性。下面以链路本地地址为例:
假如有一个router有两个网口(a和b),分别连接到了两个网络(network A 和B),
{Network A}-----Interface_a[Router]Interface_b-----{Network B}
根据地址唯一性的特性,每个网络都可以会拥有地址fe80::1,这样当router想要跟一个host/router通信的时候,仅提供一个目的地址fe80::1是不够的,因为不知道是要到Network A还是要到Network B。对于同一个router的不同接口a和b来讲,他们拥有相同的链路本地地址也是可以的,因为他们处于不同的链路。所以仅提供一个source ip也是不够的。
RFC4007引入了区域索引(zero index)或者叫区域ID(zero ID)的概念,每个Ipv6的IP可以扩展成
%
其中是Ipv6的地址,
同样的,一个Ipv6的前缀也可以表示成
%
你用Windows的命令ipconfig可以看到本地链路地址的形如fe80::xxxx:xxxx:xxxx:xxxx%4,后面的zero id,代表是你哪一个网口。
在KAME的sockaddr_in6{}结构中,有一个u_int32_t类型的成员sin6_scope_id,就是用来表示这个address的zone id的。但是在KAME的内核中,对链路本地地址还有一种zone id的表示形式,那就是把zero id嵌入到链路本地地址的第二个16bits中去,即嵌入在in6_addr{}结构中。
回想一下链路本地地址的格式:
fe80:0:0:0:{64bits interface id}
fe80后面接48bits的0,然后是64bits的接口id。
现在变成了
fe80:{zone id}:0:0:{64bits interface id}
这样做是由于历史因素和兼容性因素。KAME项目开始的时候,sockaddr_in6{}结构中并没有sin6_scope_id的字段(参见RFC2133)。嵌入形式是KAME在链路本地地址二义性问题上的变通方法,内核中所有地方,包括内核中一些与协议无关的部分,都用这种形式表示Ipv6地址。并且,这样的实现,可以是路由表,套接字API等的实现变得更简单。
目前,KAME 使用了这种“混合”方式实现zero id,当然,在把Ipv6地址传递到用户空间的时候,会消除嵌入形式,使用sin6_scope_id表示。
顺便说一句,站点本地地址(Site-Local Addresses)也有这种二义性,由于其固有的二义性带来的单播站点本地地址的复杂性超过了它们可能带来的好处,它在RFC4193中被废弃了。也许是KAME没有支持站点本地地址:)
参考《IPv6详解 卷一》