DHCPv6有状态与无状态:IPv6地址分配与SLAAC选型实战指南
先说结论把 DHCPv6 拆成有状态和无状态是 IPv6 改造里最容易让人绕晕、也最容易被低估的一个分岔口。我见过不少网络工程师在 IPv6 双栈改造时下意识按 IPv4 的思路把 DHCPv6 配成完整的有状态模式地址倒是能拿到但后面接路由器的 PD 前缀没有任何着落也有人图省事全程只做 SLAAC结果 DNS 和域名后缀没法统一下发排障时连抓包都不知道从哪里看。这篇文章就把 DHCPv6 有状态和无状态的区别、报文细节、部署选型、配置样例和踩坑记录一次性讲清楚适合正在做 IPv6 改造的网工、运维人员也适合刚入门的网络技术学习者。1. 理解有状态和无状态拨开IPv6地址下发的迷雾1.1 IPv6地址下发的两条技术路线在 IPv4 网络里地址几乎只有一种正经下发方式就是 DHCP。到了 IPv6规则变了IPv6 地址长度 128 位地址空间充裕于是协议设计者给了两条路线。第一条是 SLAAC全称 Stateless Address Autoconfiguration无状态地址自动配置。路由器周期发送 RARouter Advertisement路由器通告报文或者主机上线主动发送 RSRouter Solicitation路由器请求请求 RA主机拿到 RA 里的网络前缀后自行拼接接口标识生成一个完整的 IPv6 地址不需要向任何服务器登记。第二条是 DHCPv6路由器或专用服务器通过 DHCPv6 协议给客户端分配地址或前缀。这个流程和 IPv4 DHCP 类似服务器维护一份分配表客户端与服务器有多次报文交互。两条路线并不是互斥的。IPv6 在设计时故意把“地址获取”和“其他网络参数获取”拆开而 RA 报文里有两位关键的标志位 M 和 O用来指导客户端如何配合。正是这两个标志位把 DHCPv6 分成了有状态和无状态M1 代表地址要走受管协议也就是 DHCPv6M0 代表地址走 SLAACO1 代表其他配置DNS、搜索域、NTP要从 DHCPv6 获取。所以严格来说“无状态 DHCPv6”的意思是 DHCPv6 服务器不负责分配地址、不维护地址状态只做其他参数下发而“有状态 DHCPv6”则是服务器要维护每一个已分配地址的租约状态。很多人把“无状态”理解成“不用 DHCPv6”这是完全错误的无状态 DHCPv6 依然有 DHCPv6 的报文交互只是交互内容里没有地址分配那一项。1.2 有状态与无状态的协议定义从协议角度看有状态和无状态其实是“DHCPv6 服务器是否维护绑定状态binding”。有状态模式下服务器在收到客户端的 Solicit 后会从本地地址池里选一个地址建立一条“客户端 DUID IA_NA 分配的地址”的绑定记录然后用 Advertise 报文通知客户端。这个绑定记录有生命周期、有续租逻辑和 IPv4 DHCP 的 lease 记录很相似。正因为有记录网络管理员才能通过服务器日志准确知道“某个 IPv6 地址曾经分配给谁、什么时候分配、什么时候释放”。无状态模式下DHCPv6 服务器更像一个“参数下发器”。客户端已经用 SLAAC 从 RA 报文里拿前缀生成了自己的地址不再需要服务器分配。服务器只负责在 Reply 报文中携带 DNS、域名搜索后缀、NTP 服务器等参数。因此它不需要维护任何地址租约也没有地址池。这里的“无状态”精确含义是服务器没有地址分配状态而不是说整个网络不用 DHCPv6。很多系统把无状态模式称为“stateless DHCPv6”把有状态模式称为“stateful DHCPv6”翻译成中文就是无状态 DHCPv6 和有状态 DHCPv6。2. 报文级拆解RA标记和DHCPv6交互2.1 RA里的M/O标记决定客户端行为的开关RA 报文是 IPv6 里最容易抓到的控制面报文也是观察有状态无状态最直观的入口。ICMPv6 type 134 就是 RA里面携带路由器生存时间、前缀选项、MTU以及我们最关心的两个 bitM 和 O。M 全称 Managed address configuration flagO 全称 Other configuration flag。两者的含义分别为M1主机应该使用 DHCPv6 获取 IPv6 地址M0主机应该使用 RA 中的前缀自己生成 IPv6 地址也就是 SLAACO1主机应该使用 DHCPv6 获取除地址之外的其他配置比如 DNS 和搜索域O0主机不使用 DHCPv6 获取其他配置通常依靠 RA 中的 RDNSS 选项或手工配置获取 DNS。把这四个值组合起来就得到四种典型的部署行为MO最终客户端行为00纯 SLAAC地址自生成DNS 靠 RA RDNSS 或手工配置01无状态 DHCPv6地址自生成DNS 等参数通过 DHCPv6 获取10有状态 DHCPv6 分配地址其他参数通过 RA 或其他方式获取11完整有状态模式地址和参数都通过 DHCPv6 获取实际部署中M1/O1 最常见因为既然开了 DHCPv6顺手把 DNS 也一起发下去更省事。而 M1/O0 比较少见除非 DNS 规划确实放在其他通道里。理解这两个 flag是判断一台终端最终会用什么方式获得地址和参数的关键。很多排障到最后都会回到一句话“先看看 RA 报文里的 M/O 到底是多少。”2.2 DHCPv6的Solicit/Advertise/Request/Reply流程有状态模式下客户端在收到 M1 的 RA 后会发起四次交互Solicit、Advertise、Request、Reply。客户端向组播地址 ff02::1:2所有 DHCPv6 服务器和中继代理发送 Solicit报文里携带一个 IA_NAIdentity Association for Non-temporary Address选项请求服务器为这个 identity association 分配地址。有效的服务器回 Advertise告诉客户端自己能提供什么地址、租期多长。客户端随后从多个候选服务器里选择一个发送 Request正式请求分配。服务器收到后回复 Reply包含实际分配的地址、首选生命周期和有效生命周期。后续还有 Renew、Rebind、Release对应续租、重新绑定和释放机制和 IPv4 DHCP 很像但报文格式完全不同。无状态模式的流程要简单得多。客户端收到 M0/O1 的 RA 后不再为地址走四步流程而是直接发送一个 Information-request 报文请求服务器下发 DNS、搜索域、NTP 等参数。服务器回 Reply报文中没有 IA_NA只有其他配置选项。整个过程不需要租约不需要维护任何地址状态所以叫无状态。这也意味着如果用tcpdump抓包看到有状态模式会有 Solicit、Advertise、Request、Reply 四连而无状态模式通常只有 Information-request 和 Reply 两个报文。这个特征是我平时判断配置是否生效的第一个抓手。还有一个经常被忽略的关键点DHCPv6 不仅能分配地址还能分配前缀。IA_PD 选项是用来获取前缀的它不同于 IA_NA 获取地址。常见场景是企业出口路由器向上级 ISP 请求一个 /64、/60 或 /56 的前缀然后这个路由器再把前缀分解成多个 /64 下发给内网网段。PD 请求和地址获取使用同一套 DHCPv6 交互流程只不过 Solicit 里带的是 IA_PD 而不是 IA_NA。这个功能只通过 DHCPv6 实现SLAAC 完全替代不了。所以选型时只要拓扑里存在“下级路由器要拿前缀”就要认真评估是否启用 DHCPv6-PD严格来说 PD 也是在分配可记录的资源多数厂商会把它归入有状态能力来做。3. 有状态还是无状态部署模式与应用场景对比3.1 典型组网模式速览IPv6 网络里并不存在一个“最佳模式”只有“当前业务是否匹配的模式”。先看一张速览表把三种最常见的部署模式放到一起对比模式地址来源DNS等配置来源服务器是否维护地址状态典型场景纯 SLAACRA 前缀 客户端自生成RA RDNSS / 手工否极简接入、IoT、实验室无状态 DHCPv6RA 前缀 客户端自生成DHCPv6否办公终端、BYOD、移动网络有状态 DHCPv6DHCPv6 IA_NADHCPv6 / RA是服务器、审计场景、需要 PD 的组网纯 SLAAC 最大的优势是部署最简单路由器只需要开启 RA地址下发的逻辑就完事了连额外的服务器都不用。但它的劣势也很明显DNS 下发依赖 RA 里的 RDNSS 选项而 RDNSS 选项的缓存时间和兼容性在不同操作系统上表现并不一致地址完全由终端自己生成管理员没有集中分配记录出了问题很难定位是哪个终端在用哪个地址。无状态 DHCPv6 兼顾了 SLAAC 的地址自生成能力和 DHCPv6 的参数集中下发能力。终端继续用 RA 前缀自动算地址但 DNS、搜索域这些参数统一从 DHCPv6 服务器获取。由于服务器不维护地址租约它不需要关心地址池大小也不用处理续租风暴压力远小于有状态模式。这是目前园区办公网比较推荐的一种做法。有状态 DHCPv6 则把“地址分配”这个动作重新收回到服务器端。每个地址从哪个池、哪个时间段、给了哪个 DUID都有记录。适合对地址使用有强审计需求的场景比如服务器、打印机、门禁控制器等固定设备。另外需要给下联路由器分配前缀的 DHCPv6-PD通常也必须依赖有状态能力来维护前缀绑定关系。3.2 如何结合业务选择合适的方案选型时很多人会问“哪个更好”实际操作里应该反着问你的业务对地址可见性、终端自治能力和配置下发能力分别是什么要求如果是一般企业办公网几百上千台终端用户设备五花八门还可能需要访客 Wi-Fi、BYOD 接入。这类场景用无状态 DHCPv6 通常体验最好。终端自己生成临时地址隐私保护更好DNS 和域名后缀由 DHCPv6 统一下发修改 DNS 时只要改一处服务器配置即可。不需要逐台终端去手动配 DNS也不需要在 DHCPv6 服务器里维护大量租约记录。如果是政务、金融、医疗这类对审计要求较高的网络或者运营商城域网里的网关设备那有状态 DHCPv6 几乎是必选。管理员需要知道某个地址什么时候被哪个账号使用遇到安全事件要能快速定位终端。只有服务器端维护绑定记录才能做到。另一个典型场景是给下级路由器分配前缀企业在通过专线上行接入时上级通常只会给你一个 /56 或者 /60然后你自己通过 DHCPv6-PD 往下分配。这种 PD 分配无状态模式一般搞不定老老实实上有状态。还有一类是 IoT 和哑终端场景。传感器、摄像头、水电表这些设备数量大、状态简单、不需要每个都登记固定地址。给它们配纯 SLAAC把 DNS 配置放进 RA 的 RDNSS 里或者干脆让设备不依赖 DNS只通过 IP 访问平台这样最省事。不要为了“统一管理”硬套有状态 DHCPv6因为 IoT 设备的 DUID 和地址更新逻辑五花八门反而容易造成地址池碎片化。当然现实网络经常是几种模式混合在一起。同一个三层接口上并不限制只能用某一种模式。只要 RA 里的 M/O bit 配置正确不同网段、不同 VLAN 完全可以按业务需要选择不同模式。关键是先想清楚业务诉求再去动配置。4. 实战配置用Linux快速搭一个双模式DHCPv6环境4.1 环境准备radvd和DHCPv6服务器我习惯用 Linux 做 IPv6 协议验证因为工具链比较直接而且所有关键参数都能通过配置文件暴露出来。实验环境很简单一台 Linux 主机作为路由器/DHCPv6 服务器接一个局域网另一台 Linux 或者 Windows 作为客户端。首先在服务器上开启 IPv6 转发修改/etc/sysctl.confnet.ipv6.conf.all.forwarding 1 net.ipv6.conf.eth0.forwarding 1 net.ipv6.conf.eth0.accept_ra 0接着安装两个软件radvd负责发送 RAisc-dhcp-server里的 DHCPv6 服务负责响应 DHCPv6 请求。Debian/Ubuntu 上安装命令是apt install radvd isc-dhcp-serverradvd 的作用是让客户端知道这个链路上有一个前缀以及 M/O flag 是多少。ISC DHCPv6 服务器则处理实际 DHCPv6 报文。如果只是做纯 SLAAC只装 radvd 就够了但我们要模拟无状态和有状态两种 DHCPv6所以两个组件都装。启动前先把服务停住避免配置文件还没改就自动跑起来污染测试环境。4.2 无状态DHCPv6配置步骤无状态模式的目标是地址走 SLAACDNS 等参数走 DHCPv6。先配置 radvd让 RA 报文里 M0、O1前缀设为2001:db8:100::/64并开启AdvAutonomous on这样客户端才会用 SLAAC 自生成地址。interface eth0 { AdvSendAdvert on; AdvManagedFlag off; AdvOtherConfigFlag on; prefix 2001:db8:100::/64 { AdvOnLink on; AdvAutonomous on; }; RDNSS 2001:db8:1::53 { }; };这里的AdvOtherConfigFlag on对应 O1AdvManagedFlag off对应 M0。再配置 DHCPv6 服务器注意子网里不能写 range6因为不需要分配地址只需要下发其他参数option dhcp6.name-servers 2001:db8:1::53; option dhcp6.domain-search example.com; subnet6 2001:db8:100::/64 { }在 ISC DHCPv6 里option dhcp6.name-servers和option dhcp6.domain-search是下发 DNS 和搜索域的关键选项。不写 range6服务器就不会分配地址但它仍然会在收到 Information-request 时回复这些参数。配置完成后启动服务systemctl start radvd systemctl start isc-dhcp-server验证时在客户端网卡上抓包看 RA或者用radvdump查看本机发出的 RA 内容在客户端执行ip -6 addr应该能看到基于2001:db8:100::/64自动生成的地址。再执行dhclient -6或者让系统网络管理器触发 DHCPv6 请求抓包应该能看到 Information-request 和 ReplyReply 里带 DNS 配置。4.3 有状态DHCPv6配置步骤切换到有状态模式只需要把 RA 中的 M flag 置为 1并让 DHCPv6 服务器分配地址。radvd 配置改成interface eth0 { AdvSendAdvert on; AdvManagedFlag on; AdvOtherConfigFlag on; prefix 2001:db8:100::/64 { AdvOnLink on; AdvAutonomous off; }; };注意这里我把AdvAutonomous off了。原因是即使 M1很多操作系统依然会在 A bit 仍为 1 的情况下额外生成 SLAAC 地址。为了让测试环境严格表现出“纯有状态”的行为干脆关掉 RA 里的自动配置标志。如果实际生产环境希望保留 SLAAC 作为兜底也可以不关但需要清楚这会产生两类地址并存。DHCPv6 服务器配置则要加上 range6并可以按需配置 prefix6 来下发前缀option dhcp6.name-servers 2001:db8:1::53; subnet6 2001:db8:100::/64 { range6 2001:db8:100::100 2001:db8:100::200; prefix6 2001:db8:200:: /56; }range6告诉服务器这个子网可以分配哪些地址prefix6是用于 DHCPv6-PD 的前缀池。如果只是做地址分配不涉及下联路由器prefix6 可以不写但如果你在模拟“上级网关 下级路由器”的组网就必须给下级路由器分配一个前缀这里就要用到 prefix6。验证方法也很直接。客户端网卡重新获取地址后执行ip -6 addr看到的是2001:db8:100::100到2001:db8:100::200之间的地址而不是随机生成的后缀。抓包能看到四步完整的 Solicit、Advertise、Request、Reply 流程。如果想确认 PD在下级路由器接口抓包能看到携带 IA_PD 的 Solicit以及携带分配前缀的 Reply。如果用的是华为、思科、华三这类商业设备思路完全一样只是命令不同。核心路由器接口上需要通过 ND 配置打开managed-config-flag或other-config-flag地址池交给ipv6 dhcp pool这种命令定义。配置的关键不是背命令而是把 RA 的 M/O flag 和 DHCPv6 地址池对应清楚M1 就一定要有地址池否则客户端会一直拿不到地址O1 则只需要下发参数地址池可以没有。5. 常见问题与排查技巧实录5.1 有状态模式设备仍然生成SLAAC地址这个问题我在生产环境里踩过不止一次。明明把 RA 的 M flag 配成了 1DHCPv6 地址也正常分下去了但过一段时间发现终端接口上同时存在两个 IPv6 地址一个是 DHCPv6 分配的2001:db8:100::xxx另一个是终端用 SLAAC 生成的2001:db8:100:0:xxxx:xxxx:xxxx:xxxx。原因就是 RA 前缀选项里的 A bitAdvAutonomous仍然为 1操作系统判定“这条前缀允许 SLAAC”于是顺手又自动生成了一个地址。如果业务上只需要 DHCPv6 地址最好把 RA 里的AdvAutonomous off关掉。如果由于某些原因必须保留 SLAAC 兜底那就要在地址规划上做好预期避免应用配置里写死单个 IPv6 地址导致地址一多就不认。另外在 Linux 客户端还可以通过 sysctl 关闭指定接口的 SLAAC 能力sysctl -w net.ipv6.conf.eth0.autoconf0但这种方式依赖客户端配合不能作为网络侧的唯一控制手段。5.2 无状态DHCPv6 DNS下发失败无状态模式下最典型的故障是客户端能拿到 RA、能用 SLAAC 生成地址但 DNS 一直为空。排查时我习惯按顺序查三个点。第一点看 RA 报文的 O flag 是不是 1。很多设备默认只发了 RA没开other-config-flag客户端根本不会发起 DHCPv6 的 Information-request自然拿不到 DNS。抓到 RA 后用 Wireshark 看 ICMPv6 option 里的 Managed Address Configuration 和 Other Configuration 两个字段即可。第二点看 DHCPv6 服务器有没有在客户端所在链路监听以及有没有配置option dhcp6.name-servers。曾经遇到一个案例DHCPv6 服务器配置在多网卡机器上但是服务只监听了其中一个接口导致另一半网段拿不到配置。解决办法是确认启动参数和 interface 配置或者通过抓包确认服务器是否有回复。第三点注意客户端差异。Windows 对无状态 DHCPv6 的触发相对积极收到 O1 后会主动发 Information-request但某些 Linux 发行版在没有启用 NetworkManager 或 dhcpcd 的情况下默认只做 SLAAC不会主动去请求 DHCPv6 的其他配置。遇到 Linux 终端 DNS 为空可以先在客户端手动跑一次dhclient -6看看能不能拿到能拿到就说明网络侧没毛病问题在终端的 DHCPv6 状态机没被正确触发。5.3 DHCPv6-PD 的几个典型坑DHCPv6-PD 比地址分配更容易出错尤其是第一次做前缀下发的时候。最典型的坑是只配置了range6地址池没配置 prefix6 前缀池然后下级路由器就一直报“No prefix for IA_PD”。原因很简单服务器没有可分配的前缀资源自然回不了包。需要在 DHCPv6 服务器上位下发前缀的场景单独设置 prefix pool并且保证池子里的前缀长度足够。比如上级只给了你一个/56你需要在配置里把这一整段作为 prefix pool由路由器按需申请/60或/64而不是逐个子网手动写死。另一个坑是“无状态 DHCPv6 能不能做 PD”。很多管理员以为无状态 DHCPv6 不做地址绑定应该也能做前缀下发结果客户端请求 IA_PD 后服务器一直无响应。严格来说PD 资源需要被记录和追踪属于状态化分配。虽然少数实现允许把 PD 和地址分配分成两套流程但生产环境里我建议把 PD 视为“有状态能力”配置时统一用有状态模式来管理这样行为最可控。还有一个常见问题是前缀分配后没有及时续租。前缀的租期比地址租期长但也不是永久有效的。如果下级路由器离线重拨或者上级 DHCPv6 服务重启可能出现前缀冲突或旧前缀没有释放的情况。排查时看服务器日志里的 IA_PD 记录必要时手动释放再重新获取。5.4 排查用到的命令速查表整理一份我日常排查 DHCPv6 问题时常用的命令方便直接抄目的命令 / 工具关键输出查看接口 IPv6 地址ip -6 addr地址列表、生命周期抓取 RA / DHCPv6 报文tcpdump -i eth0 -vv icmp6 or udp port 546 or udp port 547RA 的 M/O flag、DHCPv6 报文过程查看本机发出的 RA 配置radvdump前缀、flag、RDNSS查看 DHCPv6 租约/var/lib/dhcp/dhcpd6.leasesDUID、地址、租期手动发起 DHCPv6dhclient -6 -v eth0请求过程、是否获得地址和参数强制客户端发送信息请求dhcpcd -6 eth0是否触发 Information-request抓包永远是第一步。很多时候不需要想复杂的原因先把 RA 和 DHCPv6 交互报文抓到M/O flag、IA_NA 字段、Reply 里的 option 一眼就能看出问题在哪。尤其是跨厂商对接时两边对 flag 的理解不一致抓包能直接定位是哪一侧没有按协议走。6. 个人实操中的一点体会做 IPv6 网络规划和排障这段时间我最大的感受是不要带着 IPv4 DHCP 的惯性去理解 DHCPv6。IPv4 里 DHCP 几乎是唯一标准答案但 IPv6 给了 SLAAC、无状态 DHCPv6、有状态 DHCPv6 多条路线而且它们还能混用。真正决定选哪种模式的不是“哪种更高级”而是你需要在多大程度上控制终端的地址行为。需要精细登记和审计就用有状态希望终端自治、又想集中下发 DNS 就用无状态IoT 这种重点不在管理链路上的场景就大胆开纯 SLAAC。最后再分享一个小技巧在配置链路里增加一台抓包用的 Linux 主机不管业务上线还是排障都先把 RA 报文抓下来看一遍 M/O flag。只要这两个 bit 没理解清楚后续地址获取、PD 下发、DNS 配置都可能连环出问题。把 flag 和配置对应关系记牢很多看似诡异的问题其实都能在十分钟内定位出来。
上一篇/下一篇内容由系统自动关联
返回资讯列表 →