终端插上网线,右下角转圈,最后蹦出个 169.254 开头的地址——这个场景我一年能碰上十几次。多数人的第一反应是去翻 DHCP 服务器的日志,但实际排查下来,问题往往卡在中间那台交换机上。DHCP 报文分析和交换机配置这两件事,单拎出来都是独立的技能点,可一旦把它们放在一条链路里看,价值就完全不一样了:报文是现象层,配置是原因层,中间那条排查路径才是你真正要掌握的东西。
这篇内容我打算从一个网络排障者的视角,把 DHCP 四步交互里每个字段的含义、交换机在报文转发路径上可能动的手脚、以及每一类"半截交互"对应的配置问题,按我自己实际踩过的顺序讲一遍。适合正在做企业网运维、接触过 VLAN 和三层交换但 DHCP 排查总觉得没章法的朋友,也适合想搞清楚"为什么抓包看到了 DISCOVER 却看不到 OFFER"这类问题的新手。不堆概念,重点讲怎么从一包数据反推到某一行配置。
1. DHCP 四步交互在交换机内部到底经过了什么
1.1 从 DISCOVER 到 ACK:哪些字段会被中间设备改写
先把这个报文本身拆开。DHCP 报文本质上是 BOOTP 的扩展,固定头 236 字节,后面跟一个 4 字节的 magic cookie(0x63825363),再往后就是变长的 options 字段。固定头里有几个字段是排查时的关键抓手,我在抓包时基本会第一时间把它们拉出来看:
| 字段 | 长度 | 排查时的作用 |
|---|---|---|
| op | 1 字节 | 1 是客户端请求,2 是服务器应答,方向一眼可辨 |
| xid | 4 字节 | 事务 ID,客户端随机生成,用来把一次四步交互串起来 |
| flags | 2 字节 | 最高位是广播标志,置 1 表示要求服务器用广播回复,这个位是个大坑 |
| ciaddr | 4 字节 | 客户端已有地址时填,续租和 INIT-REBOOT 场景才有值 |
| yiaddr | 4 字节 | 服务器准备分配给客户端的地址 |
| giaddr | 4 字节 | 中继代理地址,直接决定服务器从哪个地址池取地址 |
| chaddr | 16 字节 | 客户端硬件地址,前 6 字节就是 MAC |
| option 53 | 变长 | 报文类型:1 DISCOVER、2 OFFER、3 REQUEST、5 ACK、6 NAK |
除了这些,option 55(参数请求列表)能看出客户端想要哪些参数,option 60(厂商类别标识)能区分这是普通 PC、IP 话机还是 PXE 引导的机器,option 61(客户端标识)有时候不是 MAC 而是"MAC+主机名"的组合,遇到按 option 61 做绑定策略的环境,这个字段不看会绕大弯。option 82 是后加的中继代理信息,里面又分 circuit-id(通常是 VLAN 号加端口号)和 remote-id(通常是设备标识),这一项是整个 DHCP 策略化分配的核心,后面单独开一节讲。
在交换机的转发路径上,真正会被改写的字段其实不多,但每改一个都可能引发连锁反应。giaddr 会被中继设备填充,hops 每过一次中继加一,option 82 会被接入设备插入,源目 IP 和 MAC 会随广播转单播而变化。搞清楚了"谁改了谁",抓包时看到异常值就不会慌。
1.2 交换机上三个会"动手"的功能位置
一台普通二层接入交换机,默认情况下对 DHCP 报文是纯透传的,广播进来广播出去,什么都不做。但只要开了下面三个功能中的任意一个,它就从"路人"变成了"参与者":
第一个是 DHCP Snooping。它的逻辑很朴素:只允许从"信任端口"下来的服务器应答报文(OFFER、ACK、NAK)通过,从"非信任端口"上来的这类报文一律丢弃。同时它会监听 ACK,把"MAC-IP-端口-VLAN-租期"这五元组建一张绑定表。这张表既是防私接 DHCP 服务器的武器,也是后续做 IP-MAC 绑定的数据源。它动手的方式是"丢包",而且丢得悄无声息,这是排查时最容易误判的地方。
第二个是 Option 82 插入。开启后,接入设备会在客户端上行的 DHCP 报文里塞进 circuit-id 和 remote-id,让服务器知道这个请求是从哪个设备的哪个端口上来的。服务器侧可以据此做"同端口固定分配""按楼层分配不同网段"这类策略。它动手的方式是"改包",改了之后如果服务器不认这个 option,可能直接丢弃。
第三个是 DHCP 中继。跨网段场景必不可少,把客户端的广播转成单播发给指定服务器,同时把接收报文的那个三层接口地址填进 giaddr。它动手的方式是"改地址",giaddr 一填错,服务器就会从错误的池子里分配地址,客户端拿到一个本网段根本路由不到的 IP,表现是"拿到地址但上不了网"。
这三个功能在配置上是独立的,但在报文路径上是叠加的。我见过一个环境同时开了 Snooping 和 Option 82,上行口忘了配 trusted,结果就是客户端 DISCOVER 一路畅通,OFFER 全被丢在接入交换机上,抓包只能看到一半的交互。
1.3 抓包点选在哪里,决定了你能不能看到真相
这一点必须单独说,因为它决定了后面所有分析的有效性。DHCP 是广播交互,抓包点的位置不同,看到的东西完全不一样。
比较靠谱的做法是两端同时抓:客户端侧抓一份,服务器侧或者中继设备的上行口抓一份。如果只有客户端侧,你只能知道"我发了没收到";如果只有服务器侧,你只能知道"服务器收到了没回"或者"根本没收到"。两边一对比,问题立刻被压缩到中间那一段。
交换机上做端口镜像要注意方向。把接入端口作为镜像源、抓包口作为观察口,入方向(inbound)能看到客户端发的 DISCOVER 和 REQUEST,出方向(outbound)能看到服务器回来的 OFFER 和 ACK。很多环境只配了入方向,然后困惑于"为什么镜像口看不到服务器回应"——因为回应是从上行口进来的,压根没经过被镜像的那个接入口。
# 以某主流厂商CLI为例,关键词各厂商略有差异 observe-port 1 interface GigabitEthernet 0/0/20 interface GigabitEthernet 0/0/1 port-mirroring to observe-port 1 inbound port-mirroring to observe-port 1 outbound如果接入交换机是二层设备、没有可用的镜像能力,退一步的办法是在上行链路的汇聚设备上做镜像,但这时候你看到的是整个 VLAN 的 DHCP 流量,需要用抓包过滤条件把它缩到单个 MAC 或者单个 xid 上。过滤表达式我一般这么写:bootp && eth.addr == xx:xx:xx:xx:xx:xx,xid 拿到之后再改成bootp.id == 0x12345678精确锁定一次交互。
提示:镜像口带宽要留够,接入交换机上做全端口镜像很容易把观察口打满,抓包结果出现丢包,反而误导判断。只镜像需要排查的那个端口就够。
2. 抓包之前,先把交换机侧的拦截点摸清楚
2.1 Snooping 的信任端口:为什么上行口必须 trusted
这是我最常遇到的配置缺失,没有之一。DHCP Snooping 的设计初衷是防止有人在接入层私接一台设备冒充 DHCP 服务器,所以默认逻辑是"所有端口都不信任,只有我明确指定为信任的端口才放行服务器方向的报文"。
问题在于,很多环境的配置是"全局开了 snooping,接入端口也配了,唯独忘了给上行口加 trusted"。这种情况下报文路径是这样的:
- 客户端发 DISCOVER,从接入口进来,方向是客户端到服务器,Snooping 不拦,正常转发;
- 服务器回 OFFER,从上行口进来,方向和上面相反,Snooping 一看这个端口没配 trusted,直接丢弃;
- 客户端等了几秒没收到,重发 DISCOVER,循环往复。
最终现象就是客户端一直在获取地址,抓包只能看到一串重复的 DISCOVER,一个 OFFER 都没有。这时候如果去查服务器日志,会发现服务器其实正常响应了,甚至能看到分配记录——因为服务器确实发出去了,只是被中间设备吃掉了。
# 全局开启 dhcp snooping enable # 上行口(连接 DHCP 服务器或中继设备的方向)必须信任 interface GigabitEthernet 0/0/24 dhcp snooping trusted # 接入端口开启,并限制单端口可学习的用户数 interface GigabitEthernet 0/0/1 dhcp snooping enable dhcp snooping max-user 4这里有个容易混淆的点:dhcp snooping trusted配的端口,是"连接 DHCP 服务器方向"的端口,不是"连接客户端"的端口。有些同学看到接入端口也需要放行 DHCP,就给接入口也加了 trusted,结果等于把防私接功能废掉了,任何一台接在接入口上的私接路由器都能发 OFFER 抢答。
还有一个坑是级联场景。接入交换机 A 通过上行口连汇聚交换机 B,B 上开启了 Snooping 且信任端口在更上一层。这时候 A 的上行口必须 trusted,B 连接 A 的那个端口也必须 trusted,信任链要一路打通到服务器方向。少一环,OFFER 就断在那儿。
2.2 VLAN、端口隔离、STP 这些不报错的拦截者
Snooping 至少还留了个"没有 OFFER"的线索,下面这几个干扰项更隐蔽,因为它们不影响别的业务,只影响 DHCP。
VLAN 划分不一致。客户端的 DISCOVER 是广播,广播域就是 VLAN。如果接入端口划分的 VLAN 和上行口允许通过的 VLAN 对不上,报文从根上就出不去。这种情况通常伴随"整个端口所有业务都不通",比较容易发现。但也存在"VLAN 是对的,但上行口的 trunk 允许列表里漏了这个 VLAN"的情况,端口本身 up,VLAN 也配了,就是不通。
端口隔离。开启端口隔离的接入端口,默认是不能和同 VLAN 的其他端口互通的。DHCP 的场景下,客户端和服务器不在同一个端口,报文必须经过上行口。如果上行口没有被排除在隔离之外,或者隔离组的配置把上行口也划进去了,广播就被挡在端口内部。这个问题的特征是:同 VLAN 内其他端口能通,就这个端口不行,而且抓包在接入口能看到 DISCOVER,在上行口看不到。
STP 收敛。端口插上网线之后,如果不是边缘端口(edge port),要经历 listening、learning、forwarding 三个阶段,默认时长在几十秒量级。这段时间里端口是隔离的,DHCP 广播发不出去。用户感受就是"插上网线等半分钟才拿到地址"。这个不是故障,但经常被当成故障报修。解决办法是在接入端口上配边缘端口,同时对边缘端口开 BPDU 保护,防止有人把交换机接到接入口上造成环路。
interface GigabitEthernet 0/0/1 stp edged-port enable stp bpdu-protectionACL 误伤。有些环境为了"限制 DHCP 广播",会在上行口写一条 ACL 把 UDP 67/68 给拒了。这种操作我是真的见过,而且配置时间久了自己都忘了。排查的时候如果 Snooping、VLAN、STP 都排除了,一定要去看接口下的 ACL 和全局的流量策略。
2.3 端口安全与 MAC 限制引发的连锁反应
端口安全(port-security)和 DHCP Snooping 的 max-user 限制,在功能上是两套东西,但结果都是"丢包"。
端口安全的逻辑是限制一个端口下能学习到多少个源 MAC。超了之后,默认行为可能是丢弃后续 MAC 的报文,也可能是直接 shutdown 端口。如果一台终端换了网卡、或者接了一台小交换机下面挂多台设备,很容易触发。
dhcp snooping max-user限制的是单端口可建立的 DHCP 绑定表项数量。超过上限后,新的 DHCP 请求在交换机层面会被丢弃,但已经建立的租约还能继续用。这个设计会导致一个很诡异的现象:老终端正常上网,新接入的终端怎么都拿不到地址。因为端口"满载"了。
这两种限制的正确姿势是留足余量。办公工位按 1~2 个设备算,会议室、打印区可能挂小交换机,就要按实际预期放宽,或者干脆在这些位置不用端口安全,改用 IP-MAC 绑定做管控。我个人倾向于:接入端口开 snooping 但 max-user 给到 4~8,端口安全只配在确实需要限制的公共区域端口上。
还有一个连锁反应容易被忽略:开了 Snooping 之后,如果客户端发的 DHCP 报文里的源 MAC 和报文里的 chaddr 不一致(比如经过某些虚拟化环境或者 MAC 转换设备),交换机可能判定为攻击并丢弃。这种情况在虚拟机宿主机、某些 USB 网卡、以及做了 MAC 克隆的设备上偶尔会遇到。
| 拦截点 | 典型现象 | 快速验证方式 |
|---|---|---|
| Snooping 未信任 | 只有 DISCOVER,无 OFFER | 查上行口配置,临时改 trusted 测试 |
| VLAN 不一致 | 端口所有业务不通 | 查接入端口与上行 trunk 的 VLAN 列表 |
| 端口隔离 | 单端口异常,其他正常 | 查隔离组和上行口是否被排除 |
| STP 收敛慢 | 插线后延迟很久才有地址 | 查端口角色和边缘端口配置 |
| ACL 误伤 | 特定 VLAN 或时段异常 | 查接口 ACL 和匹配计数 |
| max-user 超限 | 老终端正常,新终端拿不到 | 查绑定表条目数 |
3. 按报文断点定位:四种典型半截交互的排查路径
3.1 只有 DISCOVER 没有 OFFER
这是最常见的形态,判断链路要按抓包位置分情况。
客户端侧抓到 DISCOVER,交换机上行口没抓到——说明报文在接入交换机内部就没了。优先级排序:Snooping 拦截(DISCOVER 本身不太会被拦,但某些设备会做 DHCP 报文合法性检查)、端口隔离、VLAN 不匹配、ACL。先看 VLAN,再看隔离,最后看 Snooping 和 ACL,这个顺序是因为 VLAN 问题最容易确认,一条命令的事。
上行口抓到 DISCOVER,服务器侧没抓到——说明中间还有一跳。跨网段场景下要检查中继配置是否生效,dhcp select relay和dhcp relay server-ip是不是配在了正确的三层接口上。有一个细节:中继是在接收广播的那个三层接口上配的,如果客户端所在的 VLAN 对应的 Vlanif 接口没配中继,请求就出不去。另外中继的服务器地址如果写错,报文会发到一个没有 DHCP 服务的地址上,表现为单向可见。
服务器侧抓到 DISCOVER,但没回 OFFER——这时候问题在服务器。常见原因是地址池耗尽、地址池网段与 giaddr 不匹配、服务器上配置了针对 option 82 的策略但收到的报文里没有这个 option,或者服务器做了 MAC 白名单。地址池耗尽这种情况,抓包看不到任何异常,只能靠登录服务器查池子使用率。
提示:判断"是不是地址池满了",最快的方式是拿一个已知在池子里的地址去 ping 一下,如果全是通的,基本就是满了。或者临时把租期改短,看能不能快速回收一批。
3.2 有 OFFER 却没有 REQUEST,或者 REQUEST 之后没有 ACK
这两种情况经常被混为一谈,但原因完全不同。
有 OFFER 没有 REQUEST,说明客户端收到了服务器的分配提议,但选择了不接受。可能的场景:客户端在做地址冲突检测(发 ARP 探测这个地址有没有人用),探测到冲突就发 DECLINE 报文而不是 REQUEST;客户端是双网卡环境,另一张网卡已经拿到了地址,优先级更高;客户端操作系统里手动配置了静态地址,DHCP 客户端服务处于半启用状态。抓包上区分很简单,看有没有 option 53 = 4 的 DECLINE 报文。有 DECLINE 就是地址冲突,要去查这个地址为什么被别人占着,大概率是有人手工配了静态 IP 又没做地址保留。
有 REQUEST 没有 ACK,服务器的选择是拒绝。拒绝会体现在两方面:要么服务器直接静默丢弃,要么回一个 NAK(option 53 = 6),NAK 里通常带 option 56 写明拒绝原因。NAK 的常见原因包括:REQUEST 里 requested IP(option 50)和 server identifier(option 54)指向的服务器不一致,说明有多台服务器在响应;客户端请求的地址不在服务器的池子里;租约已经过期且服务器不允许续租。
这里有一个高频坑:网络里存在两台 DHCP 服务器,一台是正式服务器,一台是某个部门自己搭的测试服务器。客户端广播 REQUEST,两台都收到了,但 REQUEST 里的 option 54 只指向了其中一台,另一台会认为"这个客户端选了别人",于是释放掉自己刚分配的地址。这种环境下经常出现"地址拿到了又没了"的循环。
3.3 拿到了地址,但地址明显不对
这类问题的判断标准很清楚:客户端拿到的 IP 网段,和它所在 VLAN 的网段对不上。
最典型的元凶是私接 DHCP 服务器。有人在办公区插了一台家用无线路由器,路由器的 LAN 口接了公司网络,它的 DHCP 服务默认开启,分配 192.168.1.x 之类的地址。客户端广播 DISCOVER,公司服务器和这台路由器同时响应,谁先到客户端就用谁。抓包特征非常明显:两个 OFFER,源 IP 不同,option 54(服务器标识)不同,分配的 yiaddr 网段也不同。这时候比的就是谁的响应快,所以会出现"有的人拿到正常地址,有的人拿到 192.168.1.x"这种随机现象。
处理方式分两步:先定位,通过 OFFER 报文的源 MAC 找到交换机上的对应端口,把端口关掉或者做端口隔离;再防护,在接入层开 Snooping 并把所有接入端口设为非信任,从根上杜绝。
第二种是中继 giaddr 配错。中继设备把接收报文的接口地址填进 giaddr,服务器根据 giaddr 所在的网段选池。如果中继配在了一个错误的 Vlanif 上,或者该接口配置了 secondary IP 导致选了另一个池,客户端就会拿到跨网段的地址。这种情况在做了地址规划调整之后特别容易发生——VLAN 划过去了,中继接口没跟着改。
第三种是Option 82 策略误匹配。服务器侧按 circuit-id 做分配策略时,如果交换机侧插入的 circuit-id 格式和服务器预期的不一致(比如一边是"VLAN+槽位+端口"的二进制,另一边按字符串解析),匹配就会落到默认池上,分配出一个不属于该位置的地址。
3.4 地址拿到了,网关也对,就是上不了网
这种情况严格来说已经超出 DHCP 的范畴了,但排查时经常一起出现,因为用户感知都是"网络不通"。DHCP 层面能确认的是:地址、掩码、网关、DNS 四个参数都正确下发了。剩下的问题在转发路径上。
我会按这个顺序过一遍:客户端 arp -a 看网关的 MAC 学没学到,学不到说明二层不通;学到了就 ping 网关,通不了说明网关侧有问题;网关通了 ping 外网地址,通不了查路由或者 NAT;地址通但域名解析失败,查 DNS 下发和服务器可达性。
有一个和 DHCP 强相关的细节:如果客户端拿到的是 /24 掩码但网关配成了别的网段,或者 option 3(路由器)下发了多个网关地址而客户端只认第一个,也会表现为"有地址上不了网"。抓包时把 ACK 里的 option 3、option 6、option 1 都展开看一眼,能省很多时间。
4. 中继场景:giaddr 和 Option 82 的改写与配置对账
4.1 giaddr 决定了服务器从哪个池子里取地址
DHCP 服务器自己并不知道客户端在哪个网段,它唯一的判断依据就是 giaddr。中继设备收到客户端的广播后,把接收该广播的三层接口地址填进 giaddr,然后单播转发给服务器,服务器拿 giaddr 去匹配自己配置的地址池。
这意味着一个很硬的规则:giaddr 必须和地址池所在的网段精确匹配。差一个掩码位都可能出问题。比如地址池是 10.1.10.0/24,中继接口配的是 10.1.10.1/23,那 giaddr 落在 10.1.10.0/23 里,服务器如果按 /24 匹配池子,可能匹配不上,也可能匹配到相邻的 10.1.11.0 池子上去。
interface Vlanif 10 ip address 10.1.10.1 255.255.255.0 dhcp select relay dhcp relay server-ip 10.1.100.10 dhcp relay server-ip 10.1.100.11配置多个 server-ip 的时候,中继默认是把请求发给所有服务器,谁先回用谁,这本身也是一种冗余设计。但如果两台服务器配置的地址池不一致,就会出现"有时候拿到这个网段的地址,有时候拿到那个网段"的随机现象。做冗余一定要保证两台服务器的池子配置完全同步。
还有一个细节:中继的源接口。有些设备允许指定中继报文的源地址,如果不指定,默认用出接口地址。在多出口或者有策略路由的环境里,源地址选错会导致回程报文走另一条路径,出现"服务器收到了请求,但应答回不来"的单通现象。抓包上看就是服务器侧有 OFFER,中继侧没有。
hops 字段在中继场景下也值得看一眼。每经过一次中继加一,超过阈值(一般是 16)报文会被丢弃。正常情况下 hops 应该是 0 或 1,如果看到 3、4 甚至更高,说明网络里存在中继环路——两台设备互相把对方的报文当中继请求转发,形成死循环。这种情况通常发生在两台三层设备都配了中继、且互相同步了路由的环境里,报文在两台设备之间来回弹。
4.2 Option 82 的插入、透传与剥离
Option 82 的价值在于让服务器知道"这个请求来自哪个物理位置",从而做精细化的地址分配。它的工作流程分三段:
插入发生在离客户端最近的那台开启了该功能的接入设备上。设备把接收报文的端口信息编码成 circuit-id(子选项 1),把设备自身标识编码成 remote-id(子选项 2),塞进报文的 option 82 字段。circuit-id 的格式各家实现不同,常见的是"VLAN ID(2 字节)+ 槽位号(1 字节)+ 端口号(1 字节)"的四字节二进制,也有用字符串格式的。
透传发生在中间的二层或三层设备上。中继设备在转发时不修改 option 82 的内容,但要保证它不被丢掉。有些设备默认会在转发前剥离 option 82,需要显式开启保留。
剥离发生在服务器应答返回客户端的最后一段。客户端是不认识 option 82 的,标准要求中继设备在把 OFFER/ACK 转发给客户端之前把它剥掉。如果设备没剥,某些客户端会直接丢弃这个报文,表现为"服务器回了但客户端不认"。
# 接入设备侧开启插入 interface GigabitEthernet 0/0/1 dhcp snooping enable dhcp snooping information enable # 中继设备侧配置保留与剥离策略(关键词各厂商不同) interface Vlanif 10 dhcp relay information enable dhcp relay information strategy keep实际踩过的坑里,最常见的是"服务器侧策略依赖 option 82,但接入设备没开插入",结果所有请求都落到默认池。第二常见的是"开了插入,但服务器软件不识别这个 option,直接丢弃报文",这种情况在换服务器或者升级服务器软件之后经常出现,因为不同实现对 option 82 的容错程度差别很大。排查时把抓包里的 option 82 展开,对照服务器侧的配置看格式和内容是否匹配,是唯一靠谱的办法。
4.3 中继和 Snooping 同时开启时的顺序问题
这两个功能在报文路径上是有先后顺序的。客户端上行的 DISCOVER 先经过 Snooping 检查(因为是客户端方向,不拦),然后进中继模块,中继模块填 giaddr、可能插入 option 82,再转发出去。服务器回来的 OFFER 先由中继模块接收并剥掉 option 82,然后交给 Snooping 检查(这个方向要被拦,所以必须从信任端口进来)。
问题就出在这个顺序上。中继设备收到 OFFER 的那个接口,在逻辑上是"服务器方向",必须配 trusted。但很多人在配中继的时候只关注了dhcp select relay和server-ip,忘了 Snooping 还在那儿守着,结果 OFFER 被自己的 Snooping 丢了。这种配置在同一个设备上既做中继又做 Snooping 的环境里特别容易出现,因为两个功能配在不同菜单下,很容易只配一半。
我自己的习惯是:只要设备上开了 Snooping,配完中继之后一定要补一条dhcp snooping trusted到面向服务器的接口上,然后抓一次包确认 OFFER 能正常返回。宁可多花五分钟验证,也别等到用户报障。
5. 从绑定表反推配置:Snooping 表的生成、查询与静态绑定
5.1 动态绑定表什么时候生成,为什么有时候是空的
Snooping 的绑定表不是凭空来的,它是在监听 DHCP ACK 报文的过程中逐条建立的。也就是说,没有完整的四步交互,就没有绑定表项。
这一点在排查时非常有用。如果你发现某台终端的绑定表项不存在,说明它的 DHCP 交互在某一步断掉了,这时候抓包就能直接定位断点在哪一步。反过来,如果绑定表里有这条记录,说明地址分配是成功的,问题不在 DHCP 层面。
# 查询全部绑定表项 display dhcp snooping user-bind all # 按接口过滤 display dhcp snooping user-bind interface GigabitEthernet 0/0/1正常的表项包含 MAC、IP、租期、VLAN、接口这几项。有几种情况会导致表项"看起来不对":
表项里的 IP 是 0.0.0.0,通常出现在客户端发 DECLINE 或者 RELEASE 之后,交换机还没来得及清理;表项存在但客户端已经下线,是因为租期没到,交换机不会主动删;同一个 MAC 出现多条记录,说明这个 MAC 在多个端口上出现过,可能是终端移动位置但旧表项没老化,也可能是 MAC 冲突。
绑定表还有个容易被忽略的用途:它可以作为 IP-MAC 绑定的数据源,配合 ARP 检测功能做准入。开了dhcp snooping check arp enable之后,交换机会检查经过的 ARP 报文,如果源 IP 和源 MAC 的对应关系不在绑定表里,就直接丢弃。这个功能对私设静态 IP 的管控很有效,但也容易误伤——服务器、打印机、网络设备这些配了静态 IP 的,必须手工加静态绑定,否则 ARP 直接被拦,表现就是"能 ping 通但业务不通"或者干脆完全不通。
5.2 静态绑定该配在哪,配错了会怎样
静态绑定的作用是把"MAC-IP-接口-VLAN"这组关系写死,不依赖 DHCP 交互。它用在两类场景:一是静态 IP 的设备需要参与 ARP 检测,二是需要给特定终端固定分配地址。
dhcp snooping user-bind static ip-address 10.1.10.20 mac-address 0011-2233-4455 interface GigabitEthernet 0/0/1 vlan 10配错的典型表现是"业务时通时不通"。比如接口写成了上行口而不是实际的接入口,ARP 检测时源接口对不上,报文被丢弃;或者 VLAN 写错,绑定关系和实际转发不在同一个广播域里。这类问题排查起来很费时间,因为绑定表的查询结果看起来是"有记录"的,只有把记录里的每个字段和实际情况逐一核对才能发现。
我个人的建议是:静态绑定尽量少配,能用 DHCP 保留地址解决的就不用静态绑定。确实需要配的,配完之后立刻用display命令查一遍,把接口、VLAN、IP、MAC 四项对照现场实际情况确认,别配完就走。
5.3 表项异常时的清理与持久化
绑定表默认存在内存里,设备重启就没了。这在正常环境下没问题,因为终端会重新走一遍 DHCP 交互重建表项。但在开了 ARP 检测的环境里,设备重启后到终端重新拿到地址之前,这段时间内的 ARP 报文全部会被丢弃,表现为"重启完交换机,一片终端短暂断网"。这个窗口期通常几分钟,取决于终端的续租周期。
解决办法是开持久化,把绑定表写到存储介质里,重启后自动恢复。命令各厂商不同,通常是dhcp snooping user-bind auto-save之类的开关。开启之后要确认存储空间够用,表项多的时候文件不小。
还有一种情况需要手工清理:终端换了网卡,MAC 变了,但旧表项还在。这时候新 MAC 走 DHCP 能拿到地址,但如果服务器分配的是同一个 IP,就会出现两个 MAC 对应同一个 IP 的表项,ARP 检测会混乱。清理单条表项的命令通常是reset dhcp snooping user-bind加上过滤条件,用的时候注意别把整个表清了,尤其是在业务高峰期。
6. 一次现场复盘:某个工位终端拿不到地址的排查记录
6.1 现象描述与第一轮假设
去年处理过一个挺典型的问题。某办公区三层的一个工位,终端插上网线之后一直显示"正在识别网络",最后落到 169.254 网段。同一个接入交换机的其他工位全部正常,同一层的其他交换机也正常。
第一轮假设列了三个:接入端口配置问题(VLAN 划错或者端口被禁用)、Snooping 拦截、终端本身网卡问题。
先做最简单的排除:把终端换到隔壁工位,能正常拿到地址,说明终端没问题;把隔壁工位的终端换到这个工位,同样拿不到地址,说明问题确实在这个端口上。
登录接入交换机,查端口配置,VLAN 划分正确,端口状态 up,没有 shutdown,没有 ACL。查 Snooping 配置,全局开启,上行口 trusted,这个端口dhcp snooping enable也配了。查绑定表,这个端口下没有任何表项。
到这里基本可以确定是报文在某个环节被丢了,但不知道丢在哪。上镜像抓包。
6.2 抓包结果推翻假设
在接入端口做双向镜像,抓了两分钟。过滤 bootp 之后,只看到这个端口发出的 DISCOVER 报文,一个 OFFER 都没有。DISCOVER 的 chaddr 是终端 MAC,源 IP 0.0.0.0,目的 255.255.255.255,报文本身完全正常。
再到上行口镜像,同样过滤 bootp,能看到这个 VLAN 里其他端口的完整四步交互,但看不到故障端口发出的那几条 DISCOVER。
这就把范围缩到了"接入端口到上行口之间"。继续查:VLAN 是通的(其他端口同 VLAN 正常),端口隔离没开,STP 状态是 forwarding,ACL 没有。
剩下一个怀疑对象:Snooping 的报文合法性检查。翻配置发现这个端口上多配了一条dhcp snooping check chaddr enable(有些设备叫dhcp snooping check mac),作用是校验 DHCP 报文里的 chaddr 字段和以太网帧的源 MAC 是否一致,不一致就丢弃。
把终端的以太网帧源 MAC 和 DHCP 报文里的 chaddr 拉出来对比,果然不一致。终端是一台装了某些网络管理软件的机器,软件做了 MAC 层的封装处理,帧头和报文里的地址对不上。
6.3 根因与最终处理
根因就是这条 chaddr 校验。这个功能本来是防攻击的——有人伪造 chaddr 来骗取地址或者做地址耗尽攻击,交换机通过校验把伪造报文丢掉。但在实际环境里,某些终端软件、虚拟化网卡、USB 网卡确实会产生帧头与 chaddr 不一致的报文,导致正常终端也被误伤。
处理方式有两种:一是把这条端口的 chaddr 校验关掉,保留其他端口的校验;二是把终端上的那个网络管理软件的处理逻辑改掉。前一种更现实,因为不能要求用户去改软件配置。
interface GigabitEthernet 0/0/1 undo dhcp snooping check chaddr enable改完之后让终端重新插拔网线,抓包立刻看到了完整的 DORA 四步交互,绑定表也生成了对应表项,问题解决。
这次排查给我的教训是:Snooping 除了"信任端口"这个明面上的拦截点,还有一堆"报文合法性检查"的隐藏开关,包括 chaddr 校验、源 MAC 校验、option 82 格式校验等等。这些开关在不同设备上的默认值不一样,有的是默认关,有的是默认开。接手一个陌生环境时,我会先把这些检查项全部列出来看一遍,而不是等到出问题再一条条试。
顺便说一句,如果当时没有做上行口的镜像对比,只在接入口抓包,看到的现象会是"DISCOVER 发出去了",很容易误判成"服务器没回应",然后跑去查服务器,方向就完全错了。两端同时抓包这件事,看起来麻烦,实际上是最省时间的做法。
排查完之后我还做了一件事:把这个接入交换机的所有端口配置导出来,和其他楼层的同型号交换机做了一次 diff,把不一致的项逐条过了一遍。结果又发现两台设备的max-user配得偏小,一台配了 1,接小交换机的工位必然会出问题。这种"顺手的事"做多了,后面报障的频率会明显下降。
最后一提,DHCP 排查里最容易忽略的其实是时间。抓包文件拿到手,第一件事看时间戳,看 DISCOVER 的重发间隔。正常的重发是 1 秒、2 秒、4 秒、8 秒这样指数退避,如果看到间隔是 0.1 秒的密集重发,那基本可以确定是客户端侧的问题而不是网络侧——正常的 DHCP 客户端不会那么急。这个细节能帮你在一分钟内判断该往哪个方向查。