作者的话
家里这套网络架构折腾了好几轮:最早是锐捷三层交换机自己发 DHCP,当小路由用;后来 OpenWrt 越来越多服务挂在上面,就开始想把 DHCP 统一收拢到 OpenWrt 上——毕竟做 DNS、DHCP、各种旁路服务,还是路由器更顺手。
这篇文章记录的是:在 “锐捷三层交换机 + OpenWrt” 的架构下,仅迁移 IPv4 DHCP 到 OpenWrt 的过程。三层交换机继续负责 VLAN 间路由,出口仍然走 OpenWrt,最终实现的是:
- 每个 VLAN 里的客户端从 OpenWrt 拿 IP;
- IPv4 网关仍然是三层交换机的各 VLAN 接口;
- 拓扑、路由几乎不动,只是改了 DHCP 角色和转发路径。
本篇文章内容由AI生成,但是所有流程均为实际操作。
摘要
需求:
-
已有:
- 锐捷 SF2910 做三层交换,所有 VLAN 的网关都在交换机上;
- OpenWrt(192.168.10.3)在 VLAN10 内部,负责上网出口。
-
目标:
- 把 DHCPv4 从三层交换机迁移到 OpenWrt;
- 保持三层交换机继续做每个 VLAN 的网关 & VLAN 间路由;
- 不在交换机上跑 DHCP Server,只做 DHCP Relay。
最终方案:
-
三层交换机:
- 关闭自身 DHCP Server,删除所有
ip dhcp pool; -
在各 VLAN 三层接口上配置:
ip helper-address 192.168.10.3把各 VLAN 的 DHCP 广播中继到 OpenWrt;
- 默认路由仍然指向 OpenWrt(不变)。
- 关闭自身 DHCP Server,删除所有
-
OpenWrt:
- LAN(192.168.10.0/24)正常用
/etc/config/dhcp; -
对其它 VLAN(20/30/40/50)的地址池,使用 dnsmasq 原生配置 写入
/etc/dnsmasq.conf:dhcp-range定义地址段;dhcp-option 3指定各 VLAN 的网关(交换机的三层接口 IP);dhcp-option 6指定 DNS 服务器。
- LAN(192.168.10.0/24)正常用
-
验证:
- 各 VLAN 客户端释放 / 重新获取 IP;
- IP 段、网关、DNS 均符合预期;
- 出口路由、VLAN 间路由与迁移前一致。
1. 拓扑背景与目标
先简单抽象一下拓扑(IPv4 部分):
-
三层交换机:
- VLAN10:
192.168.10.1/24 - VLAN20:
192.168.20.1/24 - VLAN30:
192.168.30.1/24 - VLAN40:
192.168.40.1/24 - VLAN50:
192.168.50.1/24(可选) - 原来在交换机上有:
ip dhcp pool VLAN20 / VLAN30 / VLAN40 / VLAN50 ... - VLAN10:
-
OpenWrt:
- 接在 VLAN10 内侧,IP:
192.168.10.3/24 - 对三层交换机做默认网关:
ip route 0.0.0.0 0.0.0.0 VLAN 10 192.168.10.3 - 接在 VLAN10 内侧,IP:
迁移目标:
- 所有 VLAN 的 DHCPv4 都由 OpenWrt 来发;
- 各 VLAN 的网关 仍然是三层交换机,不改为 OpenWrt;
- 不改变三层交换机的三层结构,也不把路由功能搬回 OpenWrt。
这意味着:
地址分配在 OpenWrt,三层路由在交换机。
2. DHCP 设计:为什么要用 DHCP Relay
在这种架构里,每个 VLAN 的三层网关在交换机上,而 OpenWrt 只接在 VLAN10。
如果想让 VLAN20/30/40/50 的 DHCP 请求都跑到 OpenWrt,有两种思路:
- 把 OpenWrt “拉进”每个 VLAN(在 OpenWrt 上创建 eth2.20 / eth2.30 … 子接口);
- 让三层交换机做 DHCP Relay,把各 VLAN 的 DHCP 广播封装后单播到 OpenWrt。
这里选的是 第二种,原因是:
- 不想在 OpenWrt 上创建过多 VLAN 接口;
- VLAN 间路由本来就放在三层交换机上,IPv4 层面没必要把网关拉回 OpenWrt;
- DHCP Relay 机制是标准玩法,交换机只需要知道 DHCP Server 的地址(192.168.10.3)。
核心机制:
- 客户端在 VLAN20 发出 DHCP Discover(广播);
-
三层交换机 Vlan20 接口收到后,发现配置了
ip helper-address 192.168.10.3:- 把原始广播封装成单播 UDP 包发给 192.168.10.3(OpenWrt);
- 在 DHCP 报文里填入
giaddr = 192.168.20.1(Gateway IP Address)。
- OpenWrt 上的 dnsmasq 根据
giaddr和地址池设置,返回一个属于192.168.20.0/24的地址; - 交换机再把 Offer 转回客户端。
所以,OpenWrt 不需要有 VLAN20 的接口,只要理解 “giaddr 属于哪个网段,就用哪个地址池”。
3. 三层交换机配置:关掉 DHCP,开 Relay
3.1 删除交换机上的 DHCP 池
原来配置类似:
service dhcp
ip dhcp pool VLAN20
network 192.168.20.0 255.255.255.0 192.168.20.100 192.168.20.254
dns-server 114.114.114.114
default-router 192.168.20.1
ip dhcp pool VLAN30
...
迁移的时候,需要:
configure terminal
no ip dhcp pool VLAN20
no ip dhcp pool VLAN30
no ip dhcp pool VLAN40
no ip dhcp pool VLAN50
no service dhcp
这样交换机就不会再给任何 VLAN 发 IPv4 地址了,避免出现“两个 DHCP Server 争抢”的情况。
3.2 在各 VLAN 接口上配置 ip helper-address
VLAN20 在现网中类似:
interface VLAN 20
ip directed-broadcast
ip address 192.168.20.1 255.255.255.0
! 之前就已经预留了 helper 的能力
! ip helper-address 192.168.10.3
现在需要给其它 VLAN 也加上 helper(以 20/30/40/50 为例):
interface VLAN 20
ip directed-broadcast
ip address 192.168.20.1 255.255.255.0
ip helper-address 192.168.10.3
interface VLAN 30
ip address 192.168.30.1 255.255.255.0
ip helper-address 192.168.10.3
interface VLAN 40
ip address 192.168.40.1 255.255.255.0
ip helper-address 192.168.10.3
interface VLAN 50
ip address 192.168.50.1 255.255.255.0
ip helper-address 192.168.10.3
说明:
192.168.10.3是 OpenWrt LAN 的 IPv4 地址,只在 VLAN10。- VLAN10 本身不需要 helper,因为它与 OpenWrt 在同一二层广播域,客户端可以直接广播到 OpenWrt。
默认路由保持原样:
ip route 0.0.0.0 0.0.0.0 VLAN 10 192.168.10.3
这样,三层交换机仍然把所有出网流量丢给 OpenWrt。
💡 若要进一步提高安全性,可以在三层交换机上开启 DHCP Snooping,将接入口标记为 untrusted,把连接 OpenWrt 的口标记为 trusted,防止“野路由”乱发 DHCP,这里不展开。
4. OpenWrt:用 dnsmasq 同时服务多个网段
这里有一个小坑:用纯 UCI(/etc/config/dhcp)给“远端子网”分地址非常别扭。
OpenWrt 的 start / limit 通常是基于“接口自己的 IP 网段”推导出来的,而我们现在这些网段(192.168.20/30/40/50)OpenWrt 并没有本地接口。
实测下来,最稳妥的方案是:
- LAN(192.168.10.0/24)继续用
/etc/config/dhcp的config dhcp 'lan'; - 其它 VLAN 的地址池直接写在
/etc/dnsmasq.conf里,用 dnsmasq 原生语法。
4.1 保持 LAN 的 DHCP 配置
/etc/config/dhcp 中,lan 部分类似:
config dhcp 'lan'
option interface 'lan'
option start '100'
option limit '150'
option leasetime '12h'
这段负责 192.168.10.0/24 的 DHCP 分配,不需要动。
4.2 在 /etc/dnsmasq.conf 里为 VLAN20/30/40/50 增加地址池
假设 IPv4 规划如下:
- VLAN20:192.168.20.100–254,网关 192.168.20.1
- VLAN30:192.168.30.100–254,网关 192.168.30.1
- VLAN40:192.168.40.100–254,网关 192.168.40.1
- VLAN50:192.168.50.100–254,网关 192.168.50.1
在 /etc/dnsmasq.conf 增加:
# VLAN20 HomeUser 192.168.20.0/24
dhcp-range=home,192.168.20.100,192.168.20.254,255.255.255.0,8h
dhcp-option=tag:home,3,192.168.20.1
dhcp-option=tag:home,6,114.114.114.114
# VLAN30 IOT 192.168.30.0/24
dhcp-range=iot,192.168.30.100,192.168.30.254,255.255.255.0,12h
dhcp-option=tag:iot,3,192.168.30.1
dhcp-option=tag:iot,6,114.114.114.114,8.8.8.8
# VLAN40 Guest 192.168.40.0/24
dhcp-range=guest,192.168.40.100,192.168.40.254,255.255.255.0,12h
dhcp-option=tag:guest,3,192.168.40.1
dhcp-option=tag:guest,6,192.168.10.3,114.114.114.114
# VLAN50 示例 192.168.50.0/24
dhcp-range=vlan50,192.168.50.100,192.168.50.254,255.255.255.0,8h
dhcp-option=tag:vlan50,3,192.168.50.1
dhcp-option=tag:vlan50,6,192.168.10.3,114.114.114.114
几个关键点:
-
dhcp-range=<tag>,start,end,netmask,leasetime<tag>(home/iot/guest/vlan50)只是一个标记名,后续用来dhcp-option=tag:xxx,...绑定网关/DNS;- start/end/netmask 明确写完整的 IP 和掩码,避免 UCI 那套“偏移量”的困惑。
-
dhcp-option=tag:xxx,3,<gateway>- 选项 3 = 默认网关:这里必须是各 VLAN 上三层交换机的接口 IP(192.168.20.1/30.1/40.1/50.1),而 不是 OpenWrt。
- 这样才能保持“路由走交换机”的设计。
-
dhcp-option=tag:xxx,6,<dns1>,<dns2>- 选项 6 = DNS 服务器,看个人习惯,可以用 OpenWrt 自己(192.168.10.3)再转发出去,也可以直接用公共 DNS。
最后,重启 dnsmasq:
/etc/init.d/dnsmasq restart
如果担心配置没加载,可以 logread -e dnsmasq 看一下新 range 是否被识别。
5. 验证流程与一些小坑
5.1 各 VLAN 客户端验证
以 VLAN20 为例:
-
找一台挂在 VLAN20 的机器,释放旧租约:
- Windows:
ipconfig /release→ipconfig /renew - Linux:
dhclient -r→dhclient -v
- Windows:
-
获取到新地址后检查:
- IP 是否在
192.168.20.100–254内; - 网关是否为
192.168.20.1; - DNS 是否符合
/etc/dnsmasq.conf里的设置。
- IP 是否在
-
测试连通性:
ping 192.168.20.1(三层交换机 VLAN20 网关);ping 192.168.10.3(OpenWrt LAN);ping 114.114.114.114;ping 外网域名。
VLAN30/40/50 同理。
5.2 OpenWrt 侧检查
-
查看 dnsmasq 当前生效的配置:
ps | grep dnsmasq logread -e dnsmasq -
如需更底层排查,可以在 OpenWrt 上抓包:
tcpdump -i br-lan -n port 67 or port 68观察是否能看到从
192.168.20.1(giaddr)来的 DHCP 请求,以及返回的 Offer/ACK。
5.3 三层交换机侧检查
-
确认各 VLAN 接口上的 helper:
show running-config | include helper -
若支持 DHCP relay 统计,也可以看一下转发计数是否增加。
6. 一点经验小结
这次迁移 IPv4 DHCP 到 OpenWrt,踩到的几个点,简单记一下:
-
不要急着动 IP 结构,先只换 DHCP
- 三层交换机继续做网关 + 路由,拓扑不动;
- 只把地址分配这一块搬到 OpenWrt,整体风险会小很多。
-
远端网段的 DHCP 池,UCI 写法不如直接 dnsmasq.conf 来得直接
option start/option limit这套对“非本机接口网段”其实不太友好;- 原生
dhcp-range语法反而更清晰 —— 网段是什么就写什么。
-
记得删掉交换机原来的
ip dhcp pool- 否则你会遇到“有时拿到 OpenWrt 发的 IP,有时拿到交换机发的 IP”的鬼故事。
-
DHCP Relay 的核心得靠 giaddr
- OpenWrt 不知道 VLAN20/30/40 这些名字,它只看
giaddr在哪个网段,然后用对应池; - 这也是为什么网关一定要写成各 VLAN 的 SVI IP。
- OpenWrt 不知道 VLAN20/30/40 这些名字,它只看
整体看下来,这种“DHCP 在 OpenWrt,路由在三层交换机”的结构,对家庭/小工作室挺舒服的:
一个地方集中管理 DHCP/DNS,又不牺牲三层交换的性能与拓扑弹性——如果你也刚好是锐捷 + OpenWrt 的组合,或许可以参考一下这套折腾路线。