NDP(Neighbor Discovery Protocol)NDP实现了IPv6中诸多重要机制。
路由器发现:该功能帮助设备发现链路上的路由器,并获得路由器通告的信息。
无状态自动配置:无状态自动配置是IPv6的一个亮点功能,它使得IPv6主机能够非常便捷地连入到IPv6网络中,即插即用,无需手工配置繁冗的IPv6地址,无需部署应用服务器(例如DHCP服务器)为主机分发地址。无状态自动配置机制使用到了ICMPv6中的路由器请求报文(RS)及路由器通告报文(RA)。
重复地址检测:重复地址检测是一个非常重要的机制,一个IPv6地址必须经历重复地址检测并通过检测之后才能够启用。重复地址检测用于发现链路上是否存在IPv6地址冲突。
地址解析:在IPv6中,取消了IPv4中的ARP协议,使用NDP所定义的邻居请求报文(NS)及邻居通告报文(NA)来实现地址解析功能。
邻居的状态跟踪:IPv6定义了节点之间邻居的状态机,同时还维护邻居IPv6地址与二层地址如MAC的映射关系,相应的表项存储于设备的IPv6邻居表中。
前缀重编址:IPv6路由器能够通过ICMPv6的路由器通告报文(RA)向链路上通告IPv6前缀信息。通过这种方式,主机能够从RA中所包含的前缀信息自动构建自己的IPv6单播地址。当然这些自动获取的地址是有生存时间的。通过在RA中通告IPv6地址前缀,并且灵活地设定地址的生存时间,能够实现网络中IPv6新、老前缀的平滑过渡,而无需在主机终端上消耗大量的手工劳动重新配置地址。
路由器重定向:路由器向一个IPv6节点发送ICMPv6的重定向消息,通知它在相同的本地链路上有一个更好的、到达目的地的下一跳。IPv6中的重定向功能与IPv4中的是一样的。
1. 路由器发现
(1)路由器发现功能是IPv6地址自动配置功能的基础,主要通过以下两种报文实现:
RS(路由器请求)报文:很多情况下主机接入网络后希望尽快获取网络前缀进行通信,此时主机可以立刻发送RS报文,网络上的设备将回应RA报文。RS报文的Type字段值为133。
RA(路由器通告)报文:每台设备为了让二层网络上的主机和设备知道自己的存在,可以定时以组播方式发送RA报文,RA报文中会带有网络前缀信息,及其他一些标志位信息。RA报文的Type字段值为134。
(2)主机如何获知网络的前缀(实际上不仅仅前缀前缀信息,还有其它的信息)呢?
主要通过两个途径:被动接收到网络上路由器通告(Router Advertisement),从通告中获得;主动发送路由器请求(Router Solicitation),路由器回应路由器通告后,主机从通告中获得。
(3)主机获得前缀及其它参数过程
当存在以下情况时忽略RA发送的前缀:
RA报文选项中的“auto”未置位。
前缀与已有地址前缀重复(包括link-local地址)。
RA报文选项中的“preferred lifetime”时间大于 “ valid lifetime ”。
前缀长度与接口ID长度之和不等于128位。
除以上情况外,主机获得前缀同时也获得一些相关时间参数:
“preferred lifetime”=发起新通讯的有效时间。
“ valid lifetime ”=原有通讯的有效时间。
主机会周期性的收到RA报文,并据此报文来更新自己的时间参数。
2. IPv6地址配置
(1)DHCPV6
详见DHCPV6章节
(2)IPv6地址无状态自动配置
IPv6地址无状态自动配置(StateLess Address AutoConfiguration,SLAAC)是IPv6的标准功能,相比于DHCPv6这种动态地址分配技术而言,SLAAC无需部署应用服务器,更加轻量。使用IPv6地址无状态自动配置后,设备的IPv6地址无需进行手工配置,即插即用,减轻网络管理的负担。大致的工作过程如下:
① 主机根据本地接口ID自动产生网卡的链路本地地址。
② 主机对链路本地地址进行DAD检测, 如果该地址不存在冲突则可以启用。
③ 主机发送RS报文尝试在链路上发现IPv6路由器,该报文的源地址为主机的链路本地地址。
④ 路由器回复RA报文(携带IPv6前缀信息,路由器在未收到RS时也能够配置主动发出RA报文)。
⑤ 主机根据路由器回应的RA报文,获得IPv6地址前缀信息,使用该地址前缀,加上本地产生的接口ID,形成单播IPv6地址。
⑥ 主机对生成的IPv6地址进行DAD检测,如果没有检测到冲突,那么该地址才能够启用。
3. DAD
(1)机制概述
① 重复地址检测确保网络中无两个相同的单播地址。
② 所有地址都需要做DAD。
③ 使用NS和NA完成DAD交互过程。
(2)原理
① 一个地址在通过DAD地址重复检测之前称为“tentative地址”也就是试验性地址。接口暂时还不能使用这个试验性地址进行正常的IPv6单播通讯,但是会加入和该地址所对应的Solicited-Node组播组。
② DAD重复地址检测:节点向该tentative地址所在的Solicited-Node组播地址发送一个NS,如果收到某个其他站点回应的NA,就证明该地址已被网络上使用,节点将不能使用该tentative地址通讯。
③ 接口在启用任何一个单播IPv6地址前都需要先进行DAD,包括Link-Local地址。
(3)DAD过程
在上图中,R2已是在线的设备,该设备已经使用了如图所示的地址,现在我们为R1新配置IPv6的地址2001::FFFF/64,观察一下会发生什么事情。R1的接口配置2001::FFFF/64地址后,该地址立即进入tentative状态,此时仍然是不可用的,除非该地址通过DAD检测。
R1向链路上以组播的方式发送一个NS报文,该NS的源IPv6地址为“::”,目的IPv6地址为要进行DAD检测的2001::FFFF对应的被请求节点组播地址,也就是FF02::1:FF00:FFFF。这个NS里包含着要做DAD检测的目标地址2001::FFFF。
链路上的节点都会收到这个组播的NS报文,没有配置2001::FFFF的节点接口由于没有加入该地址对应的被请求节点组播组,因此在收到这个NS的时候默默丢弃。而R2在收到这个NS后,由于它的接口配置了2001::FFFF地址,因此接口会加入组播组FF02::1:FF00:FFFF,而此刻所收到的报文又是以该地址为目的地址,因此它会解析该报文,它发现对方进行DAD的目标地址与自己本地接口地址相同,于是立即回送一个NA报文,该报文的目的地址是FF02::1,也就是所有节点组播地址,同时在报文内写入目标地址2001::FFFF,以及自己接口的MAC地址。
4. 地址解析
IPv6的地址解析不再使用ARP,也不再使用广播方式。地址解析在三层完成,针对不同的链路层协议可以采用相同的地址解析协议。地址解析过程中使用了两种ICMPv6报文:邻居请求(NS)和邻居通告(NA)。采用组播的方式发送NS消息相比于广播的方式更加的高效,也减少了对其他节点的影响和对二层网络的性能压力。可以使用三层的安全机制(例如IPSec)避免地址解析攻击。
(1)STEP1
有了NS和NA两种报文,两台主机如何获取对方的链路层地址呢?
在上图所示的场景中,PC1要请求PC2的2001::2这个地址对应的MAC地址,PC1将发送一个NS报文达到这个目的。这个NS报文的源地址是2001::1,目的地址则是2001::2对应的被请求节点组播地址。
然后IPv6数据包又被封装上数据帧的头部,其中源MAC地址是PC1的MAC地址,目的MAC地址则是2001::2这个目标地址对应的被请求节点组播地址映射得到的MAC地址,这是一个组播MAC地址。这样就完成了一个双向交互链路层地址的过程。
(2)STEP2
除R2外的其他节点也会收到这个数据帧,在读取数据帧头的时候发现目的MAC地址是一个组播MAC地址,而该组播MAC地址在本地并不侦听,因此在网卡层面就将数据帧丢弃而不再往报文里看了。
PC2收到这个数据帧后,由于本地网卡接收目的MAC地址为3333-FF00-0002的数据帧,因此在对数据帧做校验之后从帧头的类型字段得知里头是个IPv6报文,于是将帧头拆掉,把IPv6报文上送IPv6协议栈处理。IPv6协议栈从报文的IPv6头部中的目的IPv6地址得知这个数据包是发往一个被请求节点组播地址FF02::1:FF00:2,而本地网卡加入了这个组播组。接着,从IPv6包头的NextHeader字段得知IPv6包头后面封装着一个ICMPv6的报文,因此将IPv6包头拆除,将ICMPv6报文交给ICMPv6协议去处理。最后ICMPv6发现这是个NS报文,要请求自己2001::2对应的MAC地址,于是回送一个NA报文给PC1,在该报文中就包含着PC2的MAC地址。
(3) 查看IPv6邻居路由表
IPv6不像IPv4那样使用ARP表来缓存IP与MAC地址的映射,而是维护一个IPv6邻居表。在华为数通设备上则使用display ipv6 neighbors命令来查看IPv6邻居表。
5. 邻居状态跟踪
(1)邻居状态检测
实际的通讯过程中不仅仅是地址解析这么简单,而是需要维护一张邻居表,每个邻居都有相应的状态,状态之间可以迁移。邻居状态种类有5种:
① INCOMPLETE (未完成):邻居请求已发送到目标节点的请求组播地址,但没收到邻居的通告;
② REACHABLE(可达):收到确认,不续再发包确认;
③ STALE (陈旧):从收到上一次可达性确认后过了超过30s;
④ DELAY (延迟):在stale状态后发送过一个报文,并且5s内没有可达性确认;
⑤ PROBE (探查):每隔1s重传邻居请求来主动请求可达性确认,直到收到确认。
(2)邻居状态变化
IPv6的邻居关系优于IPv4的ARP,IPv6的邻居关系维护机制确保通讯发起之前邻居是可达的,而ARP本身是做不到的,仅仅通过老化机制来实现。邻居状态的迁移是比较复杂的,此处不会做详细地介绍,下面以A、B两个节点之间相互通讯过程的A节点的邻居状态变化,假设A、B两个节点之前没有任何通讯:
① A先发送NS,并生成邻居缓存条目,状态为Incomplete;
② 若B回复NA,则Incomplete->Reachable,否则10s后Incomplete->Empty,即删除条目;
③ 经过ReachableTime(默认30s),条目状态Reachable->Stale;
④ 或者在Reachable状态,收到B的非请求NA,且链路层地址不同,则马上->Stale;
⑤ 在Stale状态若A需要向B发送数据,则Stale->Delay,同时发送NS请求;
⑥ 在Delay_First_Probe_Time(默认5秒)后,Delay->Probe,其间若有NA应答,则Delay->Reachable;
⑦ 在Probe状态,每隔RetransTimer(默认1秒)发送单播NS,发送MAX_UNICAST_SOLICIT个后再等RestransTimer,有应答则->Reachable,否则进入Empty,即删除表项。
6. PMTU
前面学习的关于IPv6报文转发相关知识的时候知道,IPv6报文在转发的过程中是不进行分片操作的,当然也不进行分片报文的整合工作。IPv6报文仅在源节点进行分片,在目的节点进行组装。那么这会产生一个问题,源节点将报文到底分成多大的呢?很简单,为了所有的报文都能在路径上畅通无阻,那么分片的报文大小不能超过路径上最小的MTU,也就是PMTU——路径MTU。
RFC1981中定义了PMTU发现的机制,它是通过ICMPv6的Packet Too Big报文来完成的。首先源节点假设PMTU就是其出接口的MTU,发出报文,当转发路径上存在一个小于当前假设的PMTU时,就会向源节点发送Packet Too Big报文,并且携带自己的MTU值,此后源节点将PMTU的假设值更改为新收到的MTU值。如此反复,直到报文到达目的地之后,源节点就能知道到达某个目的地的PMTU了。
假设源到目的要先后经过4条链路,链路地MTU分别是1500、1500、1400、1300,当源发送一个分片报文的时候,首先分成1500大小的片,当到达1400的出接口时,路由器就会返回Packet Too Big错误,同时携带1400的MTU值。源接收到之后就会重新分成1400大小的片,当到达1300的出接口时,同样返回Packet Too Big错误,携带1300的MTU值。之后源重新分成1300的报文,最终到达目的地,这样就找到了该路径的PMTU。
PMTU最小为1280bytes(IPv6要求链路层所支持的MTU最小为1280)。最大PMTU由链路层决定,如隧道,可以支持很大的MTU。
7. 路由重定向
(1)重定向报文
经常网关路由器发现报文从其它网关路由器转发更好,它就会发送重定向报文告知报文的发送者,让报文发送者选择另一个网关路由器。报文格式中Type为137,Code为0;Target Address是更好的路径下一跳地址;Destination Address是需要重定向转发的报文的目的地址。
(2)重定向过程
下面是一个具体的例子,假设主机A想与主机B通讯,主机A的默认网关路由器是RTA,那么当A发送报文给B时报文会被送到RTA。
RTA接收到A发送的报文以后会发现实际上主机A直接发送给路由器R2更好,它将发送一个ICMPv6重定向报文给主机A,其中Target Address为RTB,Destination Address为主机B。
主机A接收到了重定向报文之后,会在默认路由表中添加一个主机路由,以后发往主机B的报文就直接给R2。
这就是重定向的一个简单过程,其中会有个问题:RTA如何知道去往主机B的路径通过RTB更好呢?其实这个很简单,因为RTA会发现报文进入的接口就是报文路由得出接口,也就是说发往主机B的路由实际上只是在RTA上转了一圈出来了,然后转发到RTB,据此,RTA能判断出直接给RTB是更好的路径。