
1. 先纠正一个流行说法IPv6不是不需要DHCP而是把分配和配置拆开了IPv4时代DHCP几乎是每张网的标准配置分配地址、下发网关、下发DNS一个服务搞定。到了IPv6时代很多人以为DHCPv6没什么用了——SLAAC不是能自动配地址吗结果真把设备拉上线才发现终端拿到地址了DNS全空域名解析直接失败。我接触到不少从IPv4迁到IPv6的项目前期都在DHCPv6这件事上栽过跟头。这个事得从根上讲。IPv6的自动配置体系里有两条路无状态和有状态。无状态这条路由SLAAC负责核心机制是路由器周期发送路由通告RA把前缀和前缀长度放进去主机自己拿接口标识拼出一个地址来。整个过程非常轻量不依赖任何服务器插上网线就能用这也是IPv6被宣传得零配置的底气所在。有状态这条路则交给DHCPv6由服务器集中分配地址、下发参数、维护租约逻辑上更接近IPv4里DHCP的样子。关键点在两条路不是竞争关系而是分管不同的活。SLAAC只解决有没有地址管不了地址怎么管、配置从哪来。企业网络要做地址审计管理员得知道谁在哪个网段、这个地址分给了哪台机器运营商接入网要给用户侧设备下发DNS和域名搜索列表分支机构要拿到一段可供内部再分配的前缀。这些需求SLAAC一个都满足不了。虽然RA里的RDNSS选项理论上能携带DNS甚至NTP信息但各终端系统对这个字段的实现参差不齐靠它撑生产网络我心里没底。这篇文章适合三类人正在做IPv4向IPv6迁移规划的网络工程师负责园区网、数据中心或分支互联IPv6地址分配体系的运维人员还有刚开始啃IPv6协议栈的学生。我会把DHCPv6的设计动机、报文流程、无状态/有状态的区别、中继原理和部署排障一次性讲透凡是我觉得容易踩坑的地方都会单独标出来。2. 解构DHCPv6的底层设计全新的端口、DUID和IA2.1 端口与寻址方式改成了什么DHCPv6和DHCPv4在传输层上就不是一回事。DHCPv4走UDP 67/68服务器监听67客户端用68核心手段是广播。DHCPv6改成服务器监听UDP 547客户端监听UDP 546而且基本不靠广播客户端发起请求用的是组播地址FF02::1:2这个地址叫All_DHCP_Relay_Agents_and_Servers属于链路本地范围同一链路内的所有DHCP服务器和中继代理都在这一个组播组里监听。要是服务器不在客户端的链路上怎么办还有站点范围的组播地址FF05::1:3可以用于寻址远端服务器但在实际架构里跨链路找服务器更多靠中继代理转发客户端直接发到站点范围组播的场景并不常见。IPv6协议栈里压根没有广播的概念原来IPv4里用广播完成的寻找服务动作到IPv6全被设计成组播。这个改动带来的抓包体验差异很明显不会再看到广播风暴式的Discover请求满地飞也不会看到源地址0.0.0.0、目的地址255.255.255.255那种包DHCPv6的报文全是正常的IPv6地址在互发。过滤条件也从bootp换成了dhcpv6很多老工程师第一次抓IPv6的DHCP包时找不到自己熟悉的字段就是没切换这个认知。2.2 DUID设备级唯一标识IPv4里区分客户端靠chaddr也就是网卡MAC地址。DHCPv6不这么干因为没法保证MAC唯一——虚拟机的虚拟网卡MAC可以随意改一台设备装多块网卡也很常见而且IPv6接口可以同时拥有多个地址任何一个地址都不能代表这台设备。于是有了DUID全称DHCP Unique Identifier。它是设备级别的标识和接口无关和地址无关。不管这台设备上配了哪块网卡、挂了多少个IPv6地址它发出的DHCPv6报文里带的DUID始终是同一个。这个设计的现实意义很大。需要做按设备固定分配地址的网络可以直接在DHCPv6服务器上按DUID做地址保留效果类似IPv4里的MAC绑定。但要注意DUID不是硬件指纹它通常在系统首次启用DHCPv6客户端时生成然后写进配置文件或者注册表。Linux系统一般存在/var/lib/dhcp目录下的lease文件里重新安装系统、重置网络配置都可能让它变化。系统一重装DUID就变按老DUID做的保留条目就全部失效。这个坑在IPv4时代根本不存在因为MAC还在到了IPv6时代反而成了高频问题做终端标准化文档时一定要提醒相关团队。常见的DUID有三种类型DUID-LLT由链路层地址加时间戳生成DUID-EN是企业自定义编号DUID-LL是纯链路层地址。绝大多数系统默认用DUID-LLT生成一次基本不再变除非主动删除相关状态文件。2.3 IA租约对象从一个地址升级成一组地址IPv4的租约对象就是单个IP地址服务器给客户端分配一个记录一下租期就完事。DHCPv6不是这样它引入了IA这个概念全称Identity Association可以理解成一个存放地址的容器。一个IA里可以装多个IA地址也可以装一段前缀对应前缀委派场景。每个IA有一个IAID用来区分客户端上不同的接口或不同的网络用途。IA的重要性在于IPv6的一个接口本来就要同时持有好几种地址全局单播地址、临时隐私地址、链路本地地址还可能跨多个前缀各拿一个。如果用IPv4那套一个接口一个租约的思路去管理会非常混乱。IA把一组地址打包成一个管理单元客户端可以对整组地址一起申请、续租和释放服务器也便于在一个租约单元内维护所有信息。再加上IA_PD前缀委派DHCPv6可以一次性把一段前缀分配给下级路由器让分支网络内部自己再细分。这块是DHCPv6相对IPv4最突出的能力升级也是很多纯IPv6网络架构能跑起来的基础。2.4 报文类型重新换了名字DHCPv6的报文类型和IPv4完全是两套命名拿IPv4的直觉去记一定会乱。核心四步是Solicit、Advertise、Request、Reply对应IPv4里的Discover、Offer、Request、Ack但名字不同含义也有微调。后续的Renew续租、Rebind重新绑定、Release释放、Decline拒绝、Confirm确认、Information-Request信息请求以及中继封装用的Relay-forward和Relay-reply都是独立类型编号从1到13没有一个是照抄IPv4的。DHCPv4 报文DHCPv6 报文作用DiscoverSolicit寻找可用的DHCP服务器OfferAdvertise服务器响应提供候选地址/配置RequestRequest客户端正式请求分配AckReply服务器确认并完成分配ReleaseRelease主动释放租约InformInformation-Request不申请地址只请求配置信息我见过很多同事排障时下意识说这个DHCP Offer没收到其实IPv6里根本没有Offer这个报文该查的是Advertise。这个细节看着小但在跨团队协作时很耽误事。统一用DHCPv6的报文名称沟通是迁移初期就应该养成的习惯。3. 状态化四步握手全流程拆解Solicit到Reply3.1 客户端发起Solicit状态化模式下客户端首次上线第一步是发Solicit报文。源地址通常是客户端的链路本地地址目的地址是FF02::1:2组播端口是547。报文体里会带上客户端的DUIDClient Identifier想要的IA类型比如IA_NA要地址、IA_PD要前缀以及一个请求选项列表告诉服务器我需要DNS、域名搜索列表这些信息。Solicit本质上是在问有没有服务器能给我发一段配置它不指定要哪个地址只表明需求。服务器收到以后如果觉得自己能提供就会回一个Advertise。这里有个细节如果网络里有多个DHCPv6服务器客户端会收到多个Advertise客户端有选择权标准上对服务器选择的排序没有强制规定实际实现里经常是哪个先到用哪个。3.2 服务器回应AdvertiseAdvertise是服务器对Solicit的响应里面携带着服务器自己的DUIDServer Identifier、客户端的DUID回显、可提供的IA配置包括候选地址、生命周期以及一系列配置选项。地址在这里还只是候选客户端没有正式承诺服务器也还没有真正创建租约记录。Advertise里的生命周期字段非常关键它决定客户端这个地址能用多久。首选生命周期过了之后地址不能作为新连接的源地址但已有连接不受影响有效生命周期过了地址才完全不可用。这两个值直接决定租约续租的节奏。像BGP、专线承载这类长连接业务如果地址生命周期配得太短地址失效会造成连接断流排查起来也很绕。我建议生命周期至少按业务最大连接时长来规划核心链路的地址生命周期宁可配长一些。3.3 客户端确认与服务器应答Request和Reply客户端从Advertise里挑定服务器后发Request报文目的地址还是FF02::1:2组播或者目标服务器有单播地址时也可以单播发送。Request里会带上选中的服务器DUID意思是就你了给我正式分配。服务器收到Request后正式创建租约记录然后回Reply。Reply里包含最终确认的地址、生命周期和配置选项。到了这一步客户端才算真正拿到可用的地址和配置。这里要特别提一下Reply是服务器的最终承诺客户端拿到Reply就必须按里面的参数使用地址。万一Reply里的地址和Advertise给的不一样也不奇怪一切以Reply为准。所以在抓包验证时不要只盯Solicit和Advertise要看客户端在Request里实际接受了哪个前缀的地址以及Reply最终给了什么。整个四步流程里Reply的权威性最高其他都是过程信息。3.4 续租、重新绑定与快速提交租约到期前客户端会在T1时间点发起Renew目的地址是服务器单播地址这个单播地址来自服务器之前下发的配置。Renew的含义是地址我还在用给我续一下服务器收到后回Reply并更新租约时间。如果Renew一直没有应答到T2时间点客户端就改用组播发Rebind相当于对网络里所有服务器喊话随便哪台在快来帮我确认只要有能应答的服务器就可以。这套T1/T2机制设计得挺巧T1默认是首选生命周期的50%T2是80%。调优时要结合地址生命周期和终端行为来设如果网络里有大量休眠后唤醒的终端周期太短会让唤醒后的地址处于过期状态连接表现会很奇怪。还有一个省流量的特性叫Rapid Commit。服务器配置支持的情况下客户端可以在Solicit里带一个Rapid Commit选项服务器就能跳过Advertise和中间确认的等待直接回Reply完成分配四步变两步。在终端数量大的园区网里这个特性能明显减少请求量和处理延迟但前提是网络里没有多台服务器同时应答否则容易造成配置不一致。用这个特性前先把服务器的主备协调关系理清楚。4. 无状态模式与中继代理两个容易被忽略的关键机制4.1 Information-Request只要配置、不要地址前面讲的状态化模式核心是要地址但IPv6网络里很多场景是地址完全由SLAAC负责只缺配置下发。这种场景下客户端发的是Information-Request报文服务器收到后直接回ReplyReply里只有配置选项没有地址和前缀。服务器也不需要维护租约数据库不管理地址状态所以叫无状态模式。这个设计的意义很大。运营商接入网里家庭路由器通常自己处理SLAAC但运营商还想给用户统一下发DNS配置这时在网关侧起一个无状态DHCPv6服务就够了不用管用户的地址是哪个也不用维护租约表。代价是无状态模式下拿不到任何地址审计信息谁用了什么地址、什么时间在用全靠别的渠道去查。所以我的判断是无状态模式适合只要配置、不要管理的场合需要做合规审计的政企网络建议慎选。4.2 中继代理为什么是必需品IPv4里也有DHCP Relay但DHCPv6的中继使用频率高得多很多网络架构里中继就是常态。原因是IPv6的组播报文范围通常受限客户端的Solicit发往链路本地组播服务器如果不在同一个二层域根本收不到。而IPv6网络的分层结构又决定了DHCP服务器不可能每个二层都放一台。于是中继代理成了连接客户端和服务器之间的标准通道。中继代理部署在客户端所在的接入设备或汇聚设备上它监听客户端的组播请求收到Solicit后封装成新报文发给远端服务器服务器的应答也通过中继转发回客户端。中继的存在让DHCPv6服务器可以完全集中化部署所有分支的客户端请求都汇聚到一两台服务器上处理配置和管理都集中在一个点。分支机构越多的企业中继就越离不开。4.3 Relay-forward和Relay-reply的封装逻辑中继代理工作靠两种报文类型Relay-forward和Relay-reply。中继从客户端收到原始DHCPv6报文后创建一个Relay-forward报文外层有中继自己的地址内层通过Relay Message选项把原始报文完整装进去。同时中继还会额外加Interface-ID选项标记这个请求是从哪个接口进来的这样服务器应答时能通过这个选项把数据回给正确的接入接口。服务器收到Relay-forward后解析出内层报文按正常流程处理然后把应答封装在Relay-reply里发回中继。中继再取出内层报文还原成原始DHCPv6报文按Interface-ID对应的接口转给客户端。最容易出错的点是中继接口和服务器之间的回程路由中继转发的外层地址必须是服务器能路由回去的地址否则服务器就算收到了请求应答也到不了中继。排这类问题先抓链路看Relay-forward有没有到服务器再确认回程路由顺序不能反。5. 现网部署的实战要点前缀委派、选项配置与抓包排障5.1 IA_PD给下级路由器分一段前缀而不是一个地址DHCPv6最让我觉得比IPv4高级的地方是前缀委派IA_PD。IPv4时代分支网络要么用NAT躲地址不够的问题要么手动划一个静态网段给分支再由分支自己维护子网。IPv6地址数量充裕但核心网络要统一管理地址分配于是DHCPv6服务器可以把一段前缀比如2001:db8:1080::/56分配给分支路由器分支路由器再往下把/64子网分给各个业务网段。IA_PD的租约概念跟IA_NA一样有生命周期有T1/T2只是分配的对象是前缀而不是地址。这个特性直接支撑了无NAT的纯IPv6网络和端到端可寻址这两个目标。部署要点是下游路由器开启DHCPv6 PD客户端上游路由器或服务器开启PD服务并且要规划好每级分配多少位前缀。位长规划做不好后面扩容调整会非常痛苦网络里所有下级设备的配置都得跟着动。5.2 常用的配置选项DHCPv6提供的配置选项很多但生产环境里最常用的是三个DNS递归服务器、域名搜索列表、NTP服务器。DNS和域名搜索列表的用途跟IPv4里一样但格式是IPv6地址配置时要小心别把IPv4地址格式混进去。NTP服务器这类选项在不同设备上支持程度有差异稳妥的做法是同时通过无状态DHCPv6和RA的RDNSS选项下发互为备份。我的个人习惯是在园区网的DHCPv6策略里DNS至少下发两个地址一个主一个备域名搜索列表按实际业务域名填。别小看这些很多终端对域名搜索列表的处理是拼接式的配置错了会出现很怪异的解析失败排查半天才发现是搜索列表顺序的问题。5.3 抓包怎么看排查DHCPv6问题首选还是抓包。抓包时过滤dhcpv6这个协议关键字就能看到完整报文交换。我一般按这个顺序排查先确认客户端有没有发出Solicit连Solicit都没有问题在客户端或接入链路然后看服务器有没有回Advertise没回就查服务器的监听状态和地址池里有没有可用资源再看客户端Request最终接受了哪个地址以及Reply里的生命周期是否合理。还有个容易忽略的点请求者不一定每步都用组播。Renew是单播给服务器的抓包时如果只过滤组播流量会漏掉续租包。另外中继转发的场景下客户端接入端口和服务器上联端口抓到的报文内容完全不一样只看一边很容易误判。我的习惯是两边同时抓对照起来看整个链路到底断在哪一跳。5.4 三种最常见的问题地面项目里遇到最多的DHCPv6问题就三类。第一类客户端能通过SLAAC拿到地址但DNS为空多半是RA里没有设置M位和O位终端根本不知道要去找DHCPv6。第二类DHCPv6服务器状态正常但请求到不了几乎都是中继没配好或者中继接口上没启用DHCPv6中继功能。第三类地址保留不生效原因是DUID和预期不符典型场景就是终端系统重装后DUID变了。这三类问题用常规手段都能在一个会话内定位清楚怕就怕不做抓包直接猜配置越改越乱。6. 我踩过的那些坑三则配置失误的记录6.1 只开SLAAC不开DHCPv6终端DNS全空第一次给一个园区网启用IPv6时我只在核心路由器上开了RA。地址倒是下发成功了所有终端都拿到了2001:db8:开头的地址但用户反馈网页经常打不开。抓包一看终端的DNS请求全部超时因为系统根本不知道DNS服务器在哪。RA里的RDNSS选项我虽然配了但部分老版本终端系统对这个字段的支持有兼容问题最终还是补开了无状态DHCPv6用Information-Request给终端下发DNS一切恢复正常。从那以后我的默认规范变成了启用IPv6的同时把RA的M位或O位和DHCPv6服务一起规划别省这一步。6.2 RA的M位和O位没配对第二个坑更隐蔽。有一次给分公司网络调整IPv6配置我在路由器上同时开了SLAAC和DHCPv6状态化服务但RA通告里的M位没打开。结果终端认为地址靠SLAAC配就够了根本不发DHCPv6请求DHCPv6服务器上一条租约都没生成可网络里确实同时跑着两个服务。后来把M位打开终端才重新发起完整的四步协商。这里的逻辑关系是M位代表地址由DHCPv6管理O位代表其他配置由DHCPv6管理。要用SLAAC地址加DHCPv6其他配置就只设O位不设M位要让DHCPv6管地址就两个都设。理清这个关系以后我再没犯过同类错误。6.3 中继接口忘加组播成员还有一次现网故障耗了很长时间。DHCPv6服务器在骨干部署分支网络的接入设备上开了中继功能分支内所有终端始终拿不到地址。从客户端抓包看Solicit正常发出组播也在链路上走从服务器端抓包看一个Relay-forward都没有到。最后发现接入设备的组播成员配置里FF02::1:2没有被加入到中继接口的监听列表组播请求根本没被识别成需要上送中继的报文。这个问题在文档里常常一笔带过实际配置时特别容易漏。凡是部署DHCPv6中继第一步就要确认接口对组播地址的接收和上送没有过滤。这三则经历给我最大的教训是DHCPv6调试的每一步都要拿抓包结果说话想当然地改配置只会让问题更难定位。协议本身逻辑清晰但涉及的环节多从RA标志、DHCPv6服务、中继链路到终端行为每一环都验证一遍问题基本跑不掉。希望这篇文章能帮你在IPv6落地时少走几段我走过的弯路。