IPv6地址格式、邻居发现NDP、DHCPv6、SLAAC、Path-MTU(PMTU)

IPv6地址

IPv6地址的表示方法

    IPv6地址总长度为128比特,通常分为8组,每组为4个十六进制数的形式,每组十六进制数间用冒号分隔。例如:FC00:0000:130F:0000:0000:09C0:876A:130B,这是IPv6地址的首选格式。

    为了书写方便,IPv6还提供了压缩格式,以上述IPv6地址为例,具体压缩规则为:

每组中的前导“0”都可以省略,所以上述地址可写为:FC00:0:130F:0:0:9C0:876A:130B。

地址中包含的连续两个或多个均为0的组,可以用双冒号“::”来代替,所以上述地址又可以进一步简写为:FC00:0:130F::9C0:876A:130B。

说明:

    需要注意的是,在一个IPv6地址中只能使用一次双冒号“::”,否则当计算机将压缩后的地址恢复成128位时,无法确定每个“::”代表0的个数。

如果在 IPv6 地址后面包括 TCP 或 UDP 网络端口,请始终将 IPv6 地址包括在方括号中,以便端口不会被误认为是地址的一部分。比如: [2001:db8:0:10:]:80

IPv6地址的结构

    一个IPv6地址可以分为如下两部分:

网络前缀:n比特,相当于IPv4地址中的网络ID

接口标识:128-n比特,相当于IPv4地址中的主机ID

说明:

    对于IPv6单播地址来说,如果地址的前三bit不是000,则接口标识必须为64位;如果地址的前三位是000,则没有此限制。

    接口标识可通过三种方法生成:手工配置、系统通过软件自动生成或IEEE EUI-64规范生成。其中,EUI-64规范自动生成最为常用。

    IEEE EUI-64规范是将接口的MAC地址转换为IPv6接口标识的过程。如图所示,MAC地址的前24位(用c表示的部分)为公司标识,后24位(用m表示的部分)为扩展标识符。从高位数,第7位是0表示了MAC地址本地唯一。转换的第一步将FFFE插入MAC地址的公司标识和扩展标识符之间,第二步将从高位数,第7位的0改为1表示此接口标识全球唯一。

    例如:MAC地址:000E-0C82-C4D4;转换后:020E:0CFF:FE82:C4D4。

    这种由MAC地址产生IPv6地址接口标识的方法可以减少配置的工作量,尤其是当采用无状态地址自动配置时,只需要获取一个IPv6前缀就可以与接口标识形成IPv6地址。但是使用这种方式最大的缺点是任何人都可以通过二层MAC地址推算出三层IPv6地址。

IPv6的地址分类

    IPv6地址分为单播地址、任播地址(Anycast Address)、组播地址三种类型。和IPv4相比,取消了广播地址类型,以更丰富的组播地址代替,同时增加了任播地址类型。

    IPv6单播地址

    IPv6单播地址标识了一个接口,由于每个接口属于一个节点,因此每个节点的任何接口上的单播地址都可以标识这个节点。发往单播地址的报文,由此地址标识的接口接收。

IPv6定义了多种单播地址,目前常用的单播地址有:未指定地址、环回地址、全球单播地址、链路本地地址、唯一本地地址ULA(Unique Local Address)。

未指定地址

IPv6中的未指定地址即 0:0:0:0:0:0:0:0/128 或者::/128。该地址可以表示某个接口或者节点还没有IP地址,可以作为某些报文的源IP地址(例如在NS报文的重复地址检测中会出现)。源IP地址是::的报文不会被路由设备转发。对于网络服务,::表示其正在侦听所有已配置的 IP 地址。

环回地址

IPv6中的环回地址即 0:0:0:0:0:0:0:1/128 或者::1/128。环回与IPv4中的127.0.0.1作用相同,主要用于设备给自己发送报文。该地址通常用来作为一个虚接口的地址(如Loopback接口)。实际发送的数据包中不能使用环回地址作为源IP地址或者目的IP地址。

全球单播地址

全球单播地址是带有全球单播前缀的IPv6地址,其作用类似于IPv4中的公网地址。这种类型的地址允许路由前缀的聚合,从而限制了全球路由表项的数量。这等同于范围从 2000::/16 到 3fff::/16 的所有网络。

全球单播地址由全球路由前缀(Global routing prefix)、子网ID(Subnet ID)和接口标识(Interface ID)组成,其格式如图所示:

Global routing prefix:全球路由前缀。由提供商(Provider)指定给一个组织机构,通常全球路由前缀至少为48位。目前已经分配的全球路由前缀的前3bit均为001。

Subnet ID:子网ID。组织机构可以用子网ID来构建本地网络(Site)。子网ID通常最多分配到第64位。子网ID和IPv4中的子网号作用相似。

Interface ID:接口标识。用来标识一个设备(Host)。

链路本地地址

链路本地地址是IPv6中的应用范围受限制的地址类型,只能在连接到同一本地链路的节点之间使用。它使用了特定的本地链路前缀FE80::/10(最高10位值为1111111010),同时将接口标识添加在后面作为地址的低64比特。

当一个节点启动IPv6协议栈时,启动时节点的每个接口会自动配置一个链路本地地址(其固定的前缀+EUI-64规则形成的接口标识)。这种机制使得两个连接到同一链路的IPv6节点不需要做任何配置就可以通信。所以链路本地地址广泛应用于邻居发现,无状态地址配置等应用。

以链路本地地址为源地址或目的地址的IPv6报文不会被路由设备转发到其他链路。链路本地地址的格式如图所示:

唯一本地地址

唯一本地地址是另一种应用范围受限的地址,它仅能在一个站点内使用。由于本地站点地址的废除(RFC3879),唯一本地地址被用来代替本地站点地址。这类地址划分成两个/8组: fc00::/8保留尚未定义,fd00::/8可以使用,具体使用时可以随机生成40位的前缀,与/8一起组成48位前缀,后面还是一样,16位子网+64位接口地址。

唯一本地地址的作用类似于IPv4中的私网地址,任何没有申请到提供商分配的全球单播地址的组织机构都可以使用唯一本地地址。唯一本地地址只能在本地网络内部被路由转发而不会在全球网络中被路由转发。唯一本地地址格式如图所示:

Prefix:前缀;固定为FC00::/7。

L:L标志位;值为1代表该地址为在本地网络范围内使用的地址;值为0被保留,用于以后扩展。

Global ID:全球唯一前缀;通过伪随机方式产生。

Subnet ID:子网ID;划分子网使用。

Interface ID:接口标识。

唯一本地地址具有如下特点:

具有全球唯一的前缀(虽然随机方式产生,但是冲突概率很低)。

可以进行网络之间的私有连接,而不必担心地址冲突等问题。

具有知名前缀(FC00::/7),方便边缘设备进行路由过滤。

如果出现路由泄漏,该地址不会和其他地址冲突,不会造成Internet路由冲突。

应用中,上层应用程序将这些地址看作全球单播地址对待。

独立于互联网服务提供商ISP(Internet Service Provider)。

RFC7217临时隐私地址(2017年才和rfc8064发布,需要linux内核4.0以上才支持)

    RFC 7217 IPv6更新指定了算法来生成IPv6接口标识符(以及IPv6地址),在相同网络内稳定,但随着节点从一个网络移动到另一个网络而发生变化。该算法可用以下表达式来总结和体现: 

IPv6_IID = Hash(Net_Prefix, Net_ID, Net_Iface_ID, Secret_Key) 

其中: 

Hash():加密安全哈希函数 

Net_Prefix:本地路由器发布的IPv6前缀 

Net_ID:可选网络标识符,例如WiFi网络的服务集标识符 

Net_Iface_ID:底层网络接口的标识符(例如网络接口名称) 

Secret_Key:秘密值,通常在系统安装期间作为随机值初始化,并在重新启动时保持不变 

    基本上来说,IPv6接口标识符是通过对多个参数连接计算安全散列来获得,最常见的是本地路由器(Net_Prefix)和秘密密钥(Secret_Key)公布的网络前缀。 只要节点保持在相同网络,它将维护和配置相同的IPv6地址,这是因为散列函数的所有参数保持不变。另一方面,由于网络前缀会改变,所以一旦节点连接到不同的网络,IPv6接口标识符将会改变。同时,如果节点返回到之前连接的网络,它将配置与之前相同的IPv6地址,因为用于计算该IPv6接口标识符的所有参数都将与原来情况相同。

综上,所以每个接口单播IPV6地址可能就有四个:本地链路地址、本地唯一地址、RFC7217临时隐私地址、全球唯一地址。

    IPv6组播地址

IPv6的组播与IPv4相同,用来标识一组接口,一般这些接口属于不同的节点。一个节点可能属于0到多个组播组。发往组播地址的报文被组播地址标识的所有接口接收。例如组播地址FF02::1表示链路本地范围的所有节点,组播地址FF02::2表示链路本地范围的所有路由器。

    一个IPv6组播地址由前缀,标志(Flag)字段、范围(Scope)字段以及组播组ID(Global ID)4个部分组成:

前缀:IPv6组播地址的前缀是FF00::/8。

标志字段(Flag):长度4bit,目前只使用了最后一个比特(前三位必须置0),当该位值为0时,表示当前的组播地址是由IANA所分配的一个永久分配地址;当该值为1时,表示当前的组播地址是一个临时组播地址(非永久分配地址)。

范围字段(Scope):长度4bit,用来限制组播数据流在网络中发送的范围,该字段取值和含义的对应关系如图5所示。

组播组ID(Group ID):长度112bit,用以标识组播组。目前,RFC2373并没有将所有的112位都定义成组标识,而是建议仅使用该112位的最低32位作为组播组ID,将剩余的80位都置0。这样每个组播组ID都映射到一个唯一的以太网组播MAC地址(RFC2464)。

IPv6组播地址格式如图所示:

被请求节点组播地址

被请求节点组播地址通过节点的单播或任播地址生成。当一个节点具有了单播或任播地址,就会对应生成一个被请求节点组播地址,并且加入这个组播组。一个单播地址或任播地址对应一个被请求节点组播地址。该地址主要用于邻居发现机制和地址重复检测功能。

IPv6中没有广播地址,也不使用ARP。但是仍然需要从IP地址解析到MAC地址的功能。在IPv6中,这个功能通过邻居请求NS(Neighbor Solicitation)报文完成。当一个节点需要解析某个IPv6地址对应的MAC地址时,会发送NS报文,该报文的目的IP就是需要解析的IPv6地址对应的被请求节点组播地址;只有具有该组播地址的节点会检查处理。

被请求节点组播地址由前缀FF02::1:FF00:0/104和单播地址的最后24位组成。

    IPv6任播地址

    任播地址标识一组网络接口(通常属于不同的节点)。目标地址是任播地址的数据包将发送给其中路由意义上最近的一个网络接口。

任播地址设计用来在给多个主机或者节点提供相同服务时提供冗余功能和负载分担功能。目前,任播地址的使用通过共享单播地址方式来完成。将一个单播地址分配给多个节点或者主机,这样在网络中如果存在多条该地址路由,当发送者发送以任播地址为目的IP的数据报文时,发送者无法控制哪台设备能够收到,这取决于整个网络中路由协议计算的结果。这种方式可以适用于一些无状态的应用,例如DNS等。

    IPv6中没有为任播规定单独的地址空间,任播地址和单播地址使用相同的地址空间。目前IPv6中任播主要应用于移动IPv6。

    说明:

    IPv6任播地址仅可以被分配给路由设备,不能应用于主机。任播地址不能作为IPv6报文的源地址。

子网路由器任播地址

子网路由器任播地址是已经定义好的一种任播地址(RFC3513)。发送到子网路由器任播地址的报文会被发送到该地址标识的子网中路由意义上最近的一个设备。所有设备都必须支持子网任播地址。子网路由器任播地址用于节点需要和远端子网上所有设备中的一个(不关心具体是哪一个)通信时使用。例如,一个移动节点需要和它的“家乡”子网上的所有移动代理中的一个进行通信。

子网路由器任播地址由n bit子网前缀标识子网,其余用0填充。格式如图所示:

IPv6: 兼容IPv4地址(Compatibility Address)

    为使现有网络能从IPv4平滑过渡到IPv6,需要用到一些IPv6转换机制。本文简单总结了较为流行的一些IPv6兼容地址,这些地址能够在特定转化机制下,在IPv4网络中使用(其中w.x.y.z为IPV4地址):

1. IPv4-mapped IPv6 addresses

    地址格式 ::ffff:w.x.y.z

2. ISATAP(Intra-Site Automatic Tunnel Addressing Protocal)地址

    地址格式 ::0:5EFE:w.x.y.z

    任何一个可以用在unicast地址的64位前缀,都可以用作ISATAP地址的前缀

例如Link-local地址(FE80::/64),则有Link-local ISATAP地址FE80::5EFE:w.x.y.z

    实现:Windows XP, Windows Vista, Windows 7, Windows Mobile, Linux

3. 6over4地址

    地址格式 ::wwxx:yyzz 其中ww,xx,yy,zz都是十六进制

    任何一个可以用在unicast地址的64位前缀,都可以用作6over4地址的前缀,

例如Link-local地址(FE80::/64),则有Link-local 6over4地址FE80::wwxx:yyzz

    局限:6over4需要IPv4多播支持

4. Teredo地址

    地址格式 2001::/32

    Teredo地址属于Global Unicast地址

    Teredo协议将IPv6数据包封装成IPv4 UDP包,这些数据包被转发到Teredo中继上

Teredo中继(连接到IPv6网络的Teredo节点)接收、解封这些数据包,并发送到IPv6网络上

    局限:Teredo对NAT可以支持,效果不佳。

5. 6to4地址

    地址格式 2002:wwxx:yyzz::/48 其中ww,xx,yy,zz都是十六进制

    6to4地址属于Global Unicast地址

    IPv4地址包含在IPv6地址前缀中

    和Teredo类似,6to4需要中继服务器

    地址转换示例:

Example: IPv4 address to 6to4 IPv6 address

IPv4 dec: 192 . 0 . 2 . 4

IPv4 hex: C0 . 0 . 2 . 4

IPv4 hex: C000 0204

IPv6 pre:2002:C000:0204::/48

6. IPv4-compatible地址【已弃用】

    地址格式 ::w.x.y.z

IPv6报文格式

    IPv6报文由IPv6基本报头、IPv6扩展报头以及上层协议数据单元三部分组成。

    上层协议数据单元一般由上层协议报头和它的有效载荷构成,有效载荷可以是一个ICMPv6报文、一个TCP报文或一个UDP报文。

IPv6基本报头

    IPv6基本报头有8个字段,固定大小为40字节,每一个IPv6数据报都必须包含报头。基本报头提供报文转发的基本信息,会被转发路径上面的所有设备解析。

    IPv6基本报头格式如图所示。

IPv6报头格式中主要字段解释如下:

Version:版本号,长度为4bit。对于IPv6,该值为6。

Traffic Class:流类别,长度为8bit。等同于IPv4中的TOS字段,表示IPv6数据报的类或优先级,主要应用于QoS。

Flow Label:流标签,长度为20bit。IPv6中的新增字段,用于区分实时流量,不同的流标签+源地址可以唯一确定一条数据流,中间网络设备可以根据这些信息更加高效率的区分数据流。

Payload Length:有效载荷长度,长度为16bit。有效载荷是指紧跟IPv6报头的数据报的其它部分(即扩展报头和上层协议数据单元)。该字段只能表示最大长度为65535字节的有效载荷。如果有效载荷的长度超过这个值,该字段会置0,而有效载荷的长度用逐跳选项扩展报头中的超大有效载荷选项来表示。

Next Header:下一个报头,长度为8bit。该字段定义紧跟在IPv6报头后面的第一个扩展报头(如果存在)的类型,或者上层协议数据单元中的协议类型。

Hop Limit:跳数限制,长度为8bit。该字段类似于IPv4中的Time to Live字段,它定义了IP数据报所能经过的最大跳数。每经过一个设备,该数值减去1,当该字段的值为0时,数据报将被丢弃。

Source Address:源地址,长度为128bit。表示发送方的地址。

Destination Address:目的地址,长度为128bit。表示接收方的地址。

    IPv6和IPv4相比,去除了IHL、identifiers、Flags、Fragment Offset、Header Checksum、 Options、Paddiing域,只增了流标签域,因此IPv6报文头的处理较IPv4大大简化,提高了处理效率。另外,IPv6为了更好支持各种选项处理,提出了扩展头的概念,新增选项时不必修改现有结构就能做到,理论上可以无限扩展,体现了优异的灵活性。下面为读者介绍IPv6扩展报头的一些信息。

IPv6扩展报头

    在IPv4中,IPv4报头包含可选字段Options,内容涉及security、Timestamp、Record route等,这些Options可以将IPv4报头长度从20字节扩充到60字节。在转发过程中,处理携带这些Options的IPv4报文会占用设备很大的资源,因此实际中也很少使用。

    IPv6将这些Options从IPv6基本报头中剥离,放到了扩展报头中,扩展报头被置于IPv6报头和上层协议数据单元之间。一个IPv6报文可以包含0个、1个或多个扩展报头,仅当需要设备或目的节点做某些特殊处理时,才由发送方添加一个或多个扩展头。与IPv4不同,IPv6扩展头长度任意,不受40字节限制,这样便于日后扩充新增选项,这一特征加上选项的处理方式使得IPv6选项能得以真正的利用。但是为了提高处理选项头和传输层协议的性能,扩展报头总是8字节长度的整数倍。

    当使用多个扩展报头时,前面报头的Next Header字段指明下一个扩展报头的类型,这样就形成了链状的报头列表。如图2所示,IPv6基本报头中的Next Header字段指明了第一个扩展报头的类型,而第一个扩展报头中的Next Header字段指明了下一个扩展报头的类型(如果不存在,则指明上层协议的类型)。扩展报头格式如图所示:

IPv6扩展报头中主要字段解释如下:

Next Header:下一个报头,长度为8bit。与基本报头的Next Header的作用相同。指明下一个扩展报头(如果存在)或上层协议的类型。

Extension Header Len:报头扩展长度,长度为8bit。表示扩展报头的长度(不包含Next Header字段)。

Extension Head Data:扩展报头数据,长度可变。扩展报头的内容,为一系列选项字段和填充字段的组合。

    目前,RFC 2460中定义了6个IPv6扩展头:逐跳选项报头、目的选项报头、路由报头、分段报头、认证报头、封装安全净载报头。

报头类型代表该类报头的Next Header字段值描述

逐跳选项报头0该选项主要用于为在传送路径上的每跳转发指定发送参数,传送路径上的每台中间节点都要读取并处理该字段。逐跳选项报头目前的主要应用有以下三种:

用于巨型载荷(载荷长度超过65535字节)。

用于设备提示,使设备检查该选项的信息,而不是简单的转发出去。

用于资源预留(RSVP)。

目的选项报头60目的选项报头携带了一些只有目的节点才会处理的信息。目前,目的选项报文头主要应用于移动IPv6。

路由报头43路由报头和IPv4的Loose Source and Record Route选项类似,该报头能够被IPv6源节点用来强制数据包经过特定的设备。

分段报头44同IPv4一样,IPv6报文发送也受到MTU的限制。当报文长度超过MTU时就需要将报文分段发送,而在IPv6中,分段发送使用的是分段报头。

认证报头51该报头由IPsec使用,提供认证、数据完整性以及重放保护。它还对IPv6基本报头中的一些字段进行保护。

封装安全净载报头50该报头由IPsec使用,提供认证、数据完整性以及重放保护和IPv6数据报的保密,类似于认证报头。

IPv6扩展报头规约

    当超过一种扩展报头被用在同一个分组里时,报头必须按照下列顺序出现:

IPv6基本报头

逐跳选项扩展报头

目的选项扩展报头

路由扩展报头

分段扩展报头

认证扩展报头

封装安全有效载荷扩展报头

目的选项扩展报头

上层协议数据报文

    路由设备转发时根据基本报头中Next Header值来决定是否要处理扩展头,并不是所有的扩展报头都需要被转发路由设备查看和处理的。

    除了目的选项扩展报头可能出现一次或两次(一次在路由扩展报头之前,另一次在上层协议数据报文之前),其余扩展报头只能出现一次。

ICMPv6

    ICMPv6(Internet Control Message Protocol for the IPv6)是IPv6的基础协议之一。

在IPv4中,Internet控制报文协议ICMP(Internet Control Message Protocol)向源节点报告关于向目的地传输IP数据包过程中的错误和信息。它为诊断、信息和管理目的定义了一些消息,如:目的不可达、数据包超长、超时、回应请求和回应应答等。在IPv6中,ICMPv6除了提供ICMPv4常用的功能之外,还是其它一些功能的基础,如邻接点发现、无状态地址配置(包括重复地址检测)、PMTU发现等。

    ICMPv6的协议类型号(即IPv6报文中的Next Header字段的值)为58。ICMPv6的报文格式如图所示:

报文中字段解释如下:

Type:表明消息的类型,0至127表示差错报文类型,128至255表示消息报文类型。

Code:表示此消息类型细分的类型。

Checksum:表示ICMPv6报文的校验和。

ICMPv6错误报文的分类

    ICMPv6错误报文用于报告在转发IPv6数据包过程中出现的错误。ICMPv6错误报文可以分为以下4种:

目的不可达错误报文

在IPv6节点转发IPv6报文过程中,当设备发现目的地址不可达时,就会向发送报文的源节点发送ICMPv6目的不可达错误报文,同时报文中会携带引起该错误报文的具体原因。

目的不可达错误报文的Type字段值为1。根据错误具体原因又可以细分为:

Code=0:没有到达目标设备的路由。

Code=1:与目标设备的通信被管理策略禁止。

Code=2:未指定。

Code=3:目的IP地址不可达。

Code=4:目的端口不可达。

数据包过大错误报文

在IPv6节点转发IPv6报文过程中,发现报文超过出接口的链路MTU时,则向发送报文的源节点发送ICMPv6数据包过大错误报文,其中携带出接口的链路MTU值。数据包过大错误报文是Path MTU发现机制的基础。

数据包过大错误报文的Type字段值为2,Code字段值为0。

时间超时错误报文

在IPv6报文收发过程中,当设备收到Hop Limit字段值等于0的数据包,或者当设备将Hop Limit字段值减为0时,会向发送报文的源节点发送ICMPv6超时错误报文。对于分段重组报文的操作,如果超过定时时间,也会产生一个ICMPv6超时报文。

时间超时错误报文的Type字段值为3,根据错误具体原因又可以细分为:

Code=0:在传输中超越了跳数限制。

Code=1:分片重组超时。

参数错误报文

当目的节点收到一个IPv6报文时,会对报文进行有效性检查,如果发现问题会向报文的源节点回应一个ICMPv6参数错误差错报文。

参数错误报文的Type字段值为4,根据错误具体原因又可以细分为:

Code=0:IPv6基本头或扩展头的某个字段有错误。

Code=1:IPv6基本头或扩展头的NextHeader值不可识别。

Code=2:扩展头中出现未知的选项。

ICMPv6信息报文的分类

    ICMPv6信息报文提供诊断功能和附加的主机功能,比如多播侦听发现和邻居发现。常见的ICMPv6信息报文主要包括回送请求报文(Echo Request)和回送应答报文(Echo Reply),这两种报文也就是通常使用的Ping报文。

回送请求报文:回送请求报文用于发送到目标节点,以使目标节点立即发回一个回送应答报文。回送请求报文的Type字段值为128,Code字段的值为0。

回送应答报文:当收到一个回送请求报文时,ICMPv6会用回送应答报文响应。回送应答报文的Type字段的值为129,Code字段的值为0。

邻居发现

    邻居发现协议NDP(Neighbor Discovery Protocol)是IPv6协议体系中一个重要的基础协议。邻居发现协议替代了IPv4的ARP(Address Resolution Protocol)和ICMP路由器发现(Router Discovery),它定义了使用ICMPv6报文实现地址解析,跟踪邻居状态,重复地址检测,路由器发现以及重定向等功能。

地址解析

    在IPv4中,当主机需要和目标主机通信时,必须先通过ARP协议获得目的主机的链路层地址。在IPv6中,同样需要从IP地址解析到链路层地址的功能。邻居发现协议实现了这个功能。

    ARP报文是直接封装在以太网报文中,以太网协议类型为0x0806,普遍观点认为ARP定位为第2.5层的协议。ND本身基于ICMPv6实现,以太网协议类型为0x86DD,即IPv6报文,IPv6下一个报头字段值为58,表示ICMPv6报文,由于ND协议使用的所有报文均封装在ICMPv6报文中,一般来说,ND被看作第3层的协议。在三层完成地址解析,主要带来以下几个好处:

地址解析在三层完成,不同的二层介质可以采用相同的地址解析协议。

可以使用三层的安全机制避免地址解析攻击。

使用组播方式发送请求报文,减少了二层网络的性能压力。

    地址解析过程中使用了两种ICMPv6报文:邻居请求报文NS(Neighbor Solicitation)和邻居通告报文NA(Neighbor Advertisement)。

NS报文:Type字段值为135,Code字段值为0,在地址解析中的作用类似于IPv4中的ARP请求报文。

NA报文:Type字段值为136,Code字段值为0,在地址解析中的作用类似于IPv4中的ARP应答报文。

    地址解析的过程如图所示:

    Host A在向Host B发送报文之前它必须要解析出Host B的链路层地址,所以首先Host A会发送一个NS报文,其中源地址为Host A的IPv6地址,目的地址为Host B的被请求节点组播地址,需要解析的目标IP为Host B的IPv6地址,这就表示Host A想要知道Host B的链路层地址。同时需要指出的是,在NS报文的Options字段中还携带了Host A的链路层地址。

    当Host B接收到了NS报文之后,就会回应NA报文,其中源地址为Host B的IPv6地址,目的地址为Host A的IPv6地址(使用NS报文中的Host A的链路层地址进行单播),Host B的链路层地址被放在Options字段中。这样就完成了一个地址解析的过程。

跟踪邻居状态

    通过邻居或到达邻居的通信,会因各种原因而中断,包括硬件故障、接口卡的热插入等。如果目的地失效,则恢复是不可能的,通信失败;如果路径失效,则恢复是可能的。因此节点需要维护一张邻居表,每个邻居都有相应的状态,状态之间可以迁移。

    RFC2461中定义了5种邻居状态,分别是:未完成(Incomplete)、可达(Reachable)、陈旧(Stale)、延迟(Delay)、探查(Probe)。

    邻居状态之间具体迁移过程如图所示,其中Empty表示邻居表项为空。

    下面以A、B两个邻居节点之间相互通信过程中A节点的邻居状态变化为例(假设A、B之前从未通信),说明邻居状态迁移的过程。

A先发送NS报文,并生成缓存条目,此时,邻居状态为Incomplete。

若B回复NA报文,则邻居状态由Incomplete变为Reachable,否则固定时间后邻居状态由Incomplete变为Empty,即删除表项。

经过邻居可达时间,邻居状态由Reachable变为Stale,即不确定邻居节点的可达性。

如果在Reachable状态,A收到B的非请求NA报文,且报文中携带的B的链路层地址和表项中不同,则邻居状态马上变为Stale。

在STALE状态到达老化时间后进入Delay状态。

在经过一段固定时间(5秒)后,邻居状态由Delay变为Probe,其间若有NA应答,则邻居状态由Delay变为Reachable。

在Probe状态,A每隔一定时间间隔(1秒)发送单播NS,发送固定次数(3次)后,有应答则邻居状态变为Reachable,否则邻居状态变为Empty,即删除表项。

重复地址检测

    重复地址检测DAD(Duplicate Address Detect)是在接口使用某个IPv6单播地址之前进行的,主要是为了探测是否有其它的节点使用了该地址。尤其是在地址自动配置的时候,进行DAD检测是很必要的。一个IPv6单播地址在分配给一个接口之后且通过重复地址检测之前称为试验地址(Tentative Address)。此时该接口不能使用这个试验地址进行单播通信,但是仍然会加入两个组播组:ALL-NODES组播组和试验地址所对应的Solicited-Node组播组。

    IPv6重复地址检测技术和IPv4中的免费ARP类似:节点向试验地址所对应的Solicited-Node组播组发送NS报文。NS报文中目标地址即为该试验地址。如果收到某个其他站点回应的NA报文,就证明该地址已被网络上使用,节点将不能使用该试验地址通讯。

    重复地址检测原理如图所示:

    Host A的IPv6地址FC00::1为新配置地址,即FC00::1为Host A的试验地址。Host A向FC00::1的Solicited-Node组播组发送一个以FC00::1为请求的目标地址的NS报文进行重复地址检测,由于FC00::1并未正式指定,所以NS报文的源地址为未指定地址。当Host B收到该NS报文后,有两种处理方法:

如果Host B发现FC00::1是自身的一个试验地址,则Host B放弃使用这个地址作为接口地址,并且不会发送NA报文。

如果Host B发现FC00::1是一个已经正常使用的地址,Host B会向FF02::1发送一个NA报文,该消息中会包含FC00::1。这样,Host A收到这个消息后就会发现自身的试验地址是重复的。Host A上该试验地址不生效,被标识为duplicated状态。

路由器发现

    路由器发现功能用来发现与本地链路相连的设备,并获取与地址自动配置相关的前缀和其他配置参数。

    在IPv6中,IPv6地址可以支持无状态的自动配置,即主机通过某种机制获取网络前缀信息,然后主机自己生成地址的接口标识部分。路由器发现功能是IPv6地址自动配置功能的基础,主要通过以下两种报文实现:

路由器通告RA(Router Advertisement)报文:每台设备为了让二层网络上的主机和设备知道自己的存在,定时都会组播发送RA报文,RA报文中会带有网络前缀信息,及其他一些标志位信息。RA报文的Type字段值为134。

路由器请求RS(Router Solicitation)报文:很多情况下主机接入网络后希望尽快获取网络前缀进行通信,此时主机可以立刻发送RS报文,网络上的设备将回应RA报文。RS报文的Tpye字段值为133。

    路由器发现功能如图所示:

地址自动配置

    IPv4使用DHCP实现自动配置,包括IP地址,缺省网关等信息,简化了网络管理。IPv6地址增长为128位,且终端节点多,对于自动配置的要求更为迫切,除保留了DHCP作为有状态自动配置外,还增加了无状态自动配置SLAAC。无状态自动配置即自动生成链路本地地址,主机根据RA报文的前缀信息,自动配置全球单播地址等,并获得其他相关信息。

    IPv6主机无状态自动配置过程:

根据接口标识产生链路本地地址。

发出邻居请求,进行重复地址检测。

如地址冲突,则停止自动配置,需要手工配置。

如不冲突,链路本地地址生效,节点具备本地链路通信能力。

主机会发送RS报文(或接收到设备定期发送的RA报文)。

根据RA报文中的前缀信息和接口标识得到IPv6地址。

默认路由器优先级和路由信息发现

    当主机所在的链路中存在多个设备时,主机需要根据报文的目的地址选择转发设备。在这种情况下,设备通过发布默认路由优先级和特定路由信息给主机,提高主机根据不同的目的地选择合适的转发设备的能力。

    在RA报文中,定义了默认路由优先级和路由信息两个字段,帮助主机在发送报文时选择合适的转发设备。

    主机收到包含路由信息的RA报文后,会更新自己的路由表。当主机向其他设备发送报文时,通过查询该列表的路由信息,选择合适的路由发送报文。

    主机收到包含默认设备优先级信息的RA报文后,会更新自己的默认路由列表。当主机向其他设备发送报文时,如果没有路由可选,则首先查询该列表,然后选择本链路内优先级最高的设备发送报文;如果该设备故障,主机根据优先级从高到低的顺序,依次选择其他设备。

重定向

    当网关设备发现报文从其它网关设备转发更好,它就会发送重定向报文告知报文的发送者,让报文发送者选择另一个网关设备。重定向报文也承载在ICMPv6报文中,其Type字段值为137,报文中会携带更好的路径下一跳地址和需要重定向转发的报文的目的地址等信息。

如图为一次重定向的过程:

    Host A需要和Host B通信,Host A的默认网关设备是Switch A,当Host A发送报文给Host B时报文会被送到Switch A。Switch A接收到Host A发送的报文以后会发现实际上Host A直接发送给Switch B更好,它将发送一个重定向报文给主机A,其中报文中更好的路径下一跳地址为Switch B,Destination Address为Host B。Host A接收到了重定向报文之后,会在默认路由表中添加一个主机路由,以后发往Host B的报文就直接发送给Switch B。

    当设备收到一个报文后,只有在如下情况下,设备会向报文发送者发送重定向报文:

报文的目的地址不是一个组播地址。

报文并非通过路由转发给设备。

经过路由计算后,路由的下一跳出接口是接收报文的接口。

设备发现报文的最佳下一跳IP地址和报文的源IP地址处于同一网段。

设备检查报文的源地址,发现自身的邻居表项中有用该地址作为全球单播地址或链路本地地址的邻居存在。

DHCPv6和SLAAC

DHCPv6 配置

    由于没有广播地址,DHCPv6 的工作原理与适用于 IPv4 的 DHCP 略有不同。基本上,主机将 DHCPv6 请求从其本地链接地址发送到 ff02::1:2 上的端口 547/UDP,即全 dhcp 服务器本地链接多播组。然后 DHCPv6 服务器通常向客户端的本地链接地址上的端口 564/UDP 发送一个包含相应信息的回复。

    RHEL 7 中的 dhcp 软件包提供了针对 DHCPv6 服务器的支持。

SLAAC配置

    除了 DHCPv6 之外,IPv6 也支持另外一个动态配置方法,称为无状态地址自动配置(SLAAC)。使用 SLAAC,主机通常使用本地链接 fe80::/64 地址来调出其接口。主机随后向 ff02::2(即,全路由器本地链接多组播)发送一个“路由器请求”。本地链接上的 IPv6 路由器以网络前缀以及其他可能的信息来响应主机的本地链接地址。主机随后将该网络前缀与其通常构建的接口 ID(构建方式与本地链接地址相同)配合使用。路由器定时发送多播更新(“路由器转发”)以确认或更新其提供的信息。

    EHEL 7 中的 radvd 软件包允许基于 RHEL 的 IPv6 路由器通过路由器播发来提供 SLAAC。

重要

配置为通过 DHCP 获取 IPv4 地址的典型 RHEL 7 计算机通常还配置为使用 SLAAC 来获取 IPv6 地址。当网络中添加了 IPv6 路由器时,这可能导致计算机意外获取 IPv6 地址。部分 IPv6 部署将 SLAAC 与 DHCPv6 组合,SLAAC 仅用于提供网络地址信息。而 DHCPv6 仅用于提供其他信息(如,要配置的 DNS 服务器和搜索域)。

Path MTU

    在IPv4中,报文如果过大,必须要分片进行发送,所以在每个节点发送报文之前,设备都会根据发送接口的最大传输单元MTU(Maximum Transmission Unit)来对报文进行分片。但是在IPv6中,为了减少中间转发设备的处理压力,中间转发设备不对IPv6报文进行分片,报文的分片将在源节点进行。当中间转发设备的接口收到一个报文后,如果发现报文长度比转发接口的MTU值大,则会将其丢弃;同时将转发接口的MTU值通过ICMPv6报文的“Packet Too Big”消息发给源端主机,源端主机以该值重新发送IPv6报文,这样带来了额外流量开销。PMTU发现协议可以动态发现整条传输路径上各链路的MTU值,减少由于重传带来的额外流量开销。

    PMTU协议是通过ICMPv6的Packet Too Big报文来完成的。首先源节点假设PMTU就是其出接口的MTU,发出一个试探性的报文,当转发路径上存在一个小于当前假设的PMTU时,转发设备就会向源节点发送Packet Too Big报文,并且携带自己的MTU值,此后源节点将PMTU的假设值更改为新收到的MTU值继续发送报文。如此反复,直到报文到达目的地之后,源节点就能知道到达目的地的PMTU了。

    PMTU的工作过程如图所示:

    整条传输路径需要通过4条链路,每条链路的MTU分别是1500、1500、1400、1300,当源节点发送一个分片报文的时候,首先按照PMTU为1500进行分片并发送分片报文,当到达MTU为1400的出接口时,设备返回Packet Too Big错误,同时携带MTU值为1400的信息。源节点接收到之后会将报文重新按照PMTU为1400进行分片并再次发送一个分片报文,当分片报文到达MTU值为1300的出接口时,同样返回Packet Too Big错误,携带MTU值为1300的信息。之后源节点重新按照PMTU为1300进行分片并发送分片报文,最终到达目的地,这样就找到了该路径的PMTU。

    说明:

    由于IPv6要求链路层所支持的最小MTU为1280,所以PMTU的值必须大于1280。建议用1500作为链路的PMTU值。

推荐阅读更多精彩内容