![DHCP 和 macvlan:只有第一个虚拟接口适用于单播 DHCPREQUEST](https://linux22.com/image/754957/DHCP%20%E5%92%8C%20macvlan%EF%BC%9A%E5%8F%AA%E6%9C%89%E7%AC%AC%E4%B8%80%E4%B8%AA%E8%99%9A%E6%8B%9F%E6%8E%A5%E5%8F%A3%E9%80%82%E7%94%A8%E4%BA%8E%E5%8D%95%E6%92%AD%20DHCPREQUEST.png)
我正在尝试做什么?
我正尝试通过单个物理 ISP 上行电缆上的 DHCP 获取 3 个公共 IP 地址。
出了什么问题?
更新有点不对劲。从接口来看,当 virtual0 尝试通过单播连接到 DHCP 服务器进行更新时,它工作正常。virtual1 和 virtual2 接口在单播方面失败。它们进入回退模式以使用广播并成功使用它们,但日志中充满了一些不好的东西。我正在运行 Debian 8 和 isc-dhcp-client v. 4.3.1 。
我在启动时设置了如下接口:
IF_VIRTUAL_BASE=eth0 IF_PUB0=虚拟0 IF_PUB1=虚拟1 IF_PUB2=虚拟2 IF_LAN=eth2 ifconfig "$IF_VIRTUAL_BASE" 启动 ip link 添加链接“$IF_VIRTUAL_BASE”地址 00:90:0b:ff:10:5b“$IF_PUB0”类型 macvlan ip link 设置“$IF_PUB0” ip link 添加链接“$IF_VIRTUAL_BASE”地址 00:90:0b:ff:11:5b“$IF_PUB1”类型 macvlan ip link 设置“$IF_PUB1” ip link 添加链接“$IF_VIRTUAL_BASE”地址 00:90:0b:ff:12:5b“$IF_PUB2”类型 macvlan ip link 设置“$IF_PUB2” # 启用转发 echo 1 > /proc/sys/net/ipv4/ip_forward
unset new_routers
在完成 virtual1 和 virtual2 的 dhcprequest 时我也这么做。
猜猜看,这种怪异的行为是有效的:
7 月 11 日 20:45:43 gw dhclient:virtual0 上的 DHCPREQUEST 到 255.255.255.255 端口 67 7 月 11 日 20:45:43 gw dhclient:虚拟 1 上的 DHCPREQUEST 到 255.255.255.255 端口 67 7 月 11 日 20:45:43 gw ifup[582]: virtual0 上的 DHCPREQUEST 到 255.255.255.255 端口 67 7 月 11 日 20:45:43 gw ifup[592]: 虚拟 1 上的 DHCPREQUEST 到 255.255.255.255 端口 67 7 月 11 日 20:45:43 gw dhclient:virtual2 上的 DHCPREQUEST 到 255.255.255.255 端口 67 7 月 11 日 20:45:43 gw ifup[634]: virtual2 上的 DHCPREQUEST 到 255.255.255.255 端口 67 7 月 11 日 20:45:46 gw dhclient:虚拟 1 上的 DHCPREQUEST 到 255.255.255.255 端口 67 7 月 11 日 20:45:46 gw ifup[592]: 虚拟 1 上的 DHCPREQUEST 到 255.255.255.255 端口 67 7 月 11 日 20:45:46 gw dhclient:来自 88.113.75.2 的 DHCPACK 7 月 11 日 20:45:46 gw ifup[592]: 来自 88.113.75.2 的 DHCPACK 7 月 11 日 20:45:46 gw 记录器:virtual1(重新启动):IP:-> 88.113.75.59;GW:-> 88.113.75.1 7 月 11 日 20:45:47 gw dhclient:virtual0 上的 DHCPREQUEST 到 255.255.255.255 端口 67 7 月 11 日 20:45:47 gw ifup[582]: virtual0 上的 DHCPREQUEST 到 255.255.255.255 端口 67 7 月 11 日 20:45:47 gw dhclient:来自 88.113.75.2 的 DHCPACK 7 月 11 日 20:45:47 gw ifup[582]: 来自 88.113.75.2 的 DHCPACK 7 月 11 日 20:45:47 gw 记录器:virtual0(重新启动):IP:-> 88.113.75.65;GW:-> 88.113.75.1 7 月 11 日 20:45:50 gw dhclient:virtual2 上的 DHCPREQUEST 到 255.255.255.255 端口 67 7 月 11 日 20:45:50 gw ifup[634]: virtual2 上的 DHCPREQUEST 到 255.255.255.255 端口 67 7 月 11 日 20:45:50 gw dhclient:来自 88.113.75.2 的 DHCPACK 7 月 11 日 20:45:50 gw ifup[634]: 来自 88.113.75.2 的 DHCPACK 7 月 11 日 20:45:50 gw 记录器:virtual2(重新启动):IP:-> 88.113.75.61;GW:-> 88.113.75.1
所以它们起作用了,对吧?而且它们是广播请求。好的,快进一个小时左右,我们得到了以下信息:
7 月 11 日 21:45:09 gw dhclient:virtual2 上的 DHCPREQUEST 到 195.74.6.55 端口 67 7 月 11 日 21:45:11 gw dhclient:virtual1 上的 DHCPREQUEST 到 195.74.6.55 端口 67 7 月 11 日 21:45:22 gw dhclient:virtual2 上的 DHCPREQUEST 到 195.74.6.55 端口 67 7 月 11 日 21:45:25 gw dhclient:virtual1 上的 DHCPREQUEST 到 195.74.6.55 端口 67 7 月 11 日 21:45:32 gw dhclient:virtual1 上的 DHCPREQUEST 到 195.74.6.55 端口 67 7 月 11 日 21:45:43 gw dhclient:virtual2 上的 DHCPREQUEST 到 195.74.6.55 端口 67 7 月 11 日 21:45:46 gw dhclient:virtual1 上的 DHCPREQUEST 到 195.74.6.55 端口 67 7 月 11 日 21:45:56 gw dhclient:virtual2 上的 DHCPREQUEST 到 195.74.6.55 端口 67 7 月 11 日 21:46:05 gw dhclient:virtual1 上的 DHCPREQUEST 到 195.74.6.55 端口 67 7 月 11 日 21:46:11 gw dhclient:virtual2 上的 DHCPREQUEST 到 195.74.6.55 端口 67 7 月 11 日 21:46:21 gw dhclient:virtual1 上的 DHCPREQUEST 到 195.74.6.55 端口 67 7 月 11 日 21:46:30 gw dhclient:virtual2 上的 DHCPREQUEST 发送至 195.74.6.55 端口 67 7 月 11 日 21:46:33 gw dhclient:virtual1 上的 DHCPREQUEST 到 195.74.6.55 端口 67 7 月 11 日 21:46:42 gw dhclient:virtual2 上的 DHCPREQUEST 到 195.74.6.55 端口 67 7 月 11 日 21:46:47 gw dhclient:virtual1 上的 DHCPREQUEST 到 195.74.6.55 端口 67 7 月 11 日 21:47:00 gw dhclient:virtual2 上的 DHCPREQUEST 发送至 195.74.6.55 端口 67 7 月 11 日 21:47:01 gw dhclient:virtual1 上的 DHCPREQUEST 到 195.74.6.55 端口 67 7 月 11 日 21:47:09 gw dhclient:virtual1 上的 DHCPREQUEST 到 195.74.6.55 端口 67
virtual1 和 virtual2 接口拼命尝试通过与之前的 DHCP 服务器 195.74.6.55 的单播连接来更新其 IP。它们因单播而失败。但接下来发生了一些有趣的事情,最终它们切换到广播作为后备并成功了!
7 月 11 日 22:30:41 gw dhclient:virtual1 上的 DHCPREQUEST 到 195.74.6.55 端口 67 7 月 11 日 22:30:47 gw dhclient:virtual2 上的 DHCPREQUEST 到 195.74.6.55 端口 67 7 月 11 日 22:30:52 gw dhclient:虚拟 1 上的 DHCPREQUEST 到 255.255.255.255 端口 67 7 月 11 日 22:30:52 gw dhclient:来自 88.113.75.2 的 DHCPACK 7 月 11 日 22:30:52 gw 记录器:virtual1(更新):IP:88.113.75.59 -> 88.113.75.59;GW:88.113.75.1 -> 88.113.75.1 7 月 11 日 22:30:58 gw dhclient:virtual2 上的 DHCPREQUEST 到 255.255.255.255 端口 67 7 月 11 日 22:30:58 gw dhclient:来自 88.113.75.2 的 DHCPACK 7 月 11 日 22:30:59 gw 记录器:virtual2(更新):IP:88.113.75.61 -> 88.113.75.61;GW:88.113.75.1 -> 88.113.75.1
观察virtual0接口:
7 月 11 日 22:38:17 gw dhclient:virtual0 上的 DHCPREQUEST 到 195.74.6.55 端口 67 7 月 11 日 22:38:18 gw dhclient:来自 195.74.6.55 的 DHCPACK 7 月 11 日 22:38:18 gw 记录器:virtual0(更新):IP:88.113.75.65 -> 88.113.75.65;GW:88.113.75.1 -> 88.113.75.1
结论是,对于虚拟 0 接口,单播 (dhclient) DHCP 请求有效,而对于虚拟 1 和虚拟 2,只有广播 DHCP 更新有效。所以,这一定是路由问题,对吧?以下是 ip route 在典型启动后显示的内容:
root@gw:~# ip 路由 默认通过 88.113.75.1 dev virtual0 88.113.75.0/24 dev virtual0 proto 内核范围链接 src 88.113.75.65 88.113.75.0/24 dev virtual1 proto 内核范围链接 src 88.113.75.59 88.113.75.0/24 dev virtual2 proto 内核范围链接 src 88.113.75.61 172.16.8.0/28 通过 172.16.8.2 dev tun0 # 对于 openvpn 172.16.8.0/24 dev eth2 proto kernel scope link src 172.16.8.254 # 对于 LAN 172.16.8.2 dev tun0 proto kernel scope link src 172.16.8.1 #对于 openvpn
如何使基于 macvlan 的接口 virtual1 和 virtual2 上的 dhclient 正确路由其单播续订请求并适当地接收响应?
我在 Google 上搜索了很多次,尝试过改变许多设置,包括防火墙策略、基于策略的路由、eth0 promisc 模式和 sysctl 变量、剥离通用网络设置等。我目前正在 dhclient 上进行 strace。这些设置中的一个组合必须有效。如果需要更多信息,我非常乐意提供。
编辑1:dhclient strace 已准备就绪。
这在一开始就会发生:
绑定(5,{sa_family = AF_PACKET,proto = 0x7669,if1635087474,pkttype = PACKET_HOST,addr(0)={12652,},16)= 0 绑定(6,{sa_family = AF_INET,sin_port = htons(68),sin_addr = inet_addr(“0.0.0.0”)},16)= 0 sendto(5, "......", 342, 0, {sa_family=AF_PACKET, proto=0x7669, if1635087474, pkttype=PACKET_HOST, addr(0)={12652, }, 18) = 342
据我所知,“sendto(5)”是第一次成功的基于广播的 dhclient 发送。
然后,第一个失败的单播发送:
sendto(6, "......", 300, 0, {sa_family=AF_INET, sin_port=htons(67), sin_addr=inet_addr("195.74.6.55")}, 16) = 300
下一次成功广播发送:
sendto(5, "......", 342, 0, {sa_family=AF_PACKET, proto=0x7669, if1635087474, pkttype=PACKET_HOST, addr(0)={12652, }, 18) = 342
答案1
我能够修复它!虽然方法有点不寻常,但还是可以的。
那么我做了什么?我只是卸载了 isc-dhcp-client 4.3.1 并安装了 dhcpcd 6.0.5(由 Roy Marples 开发,debian 软件包名称为 dhcpcd5)。就是这样。
我在 23:00 左右重启了机器,检查所有接口是否正常,然后设置 tcpdump 运行。大约在 00:02 时,其中一个 DHCP 计时器到期,所有 3 个接口都顺利地获得了 IP 地址,没有任何问题:
https://i.stack.imgur.com/xGQpq.png
基本上我不需要更改 /etc/dhcpcd.conf 中的任何内容。看来 dhcpcd 的构建方式比 dhclient 更智能。至少在我的场景中是这样。
(旁注:我必须说从 isc-dhcp-client 迁移到 dhcpcd 非常容易。Debian 8 具有内置支持;似乎如果你安装 dhcpcd5 并删除 isc-dhcp-client 并重新启动,系统就会自动选择新的客户端。关于脚本,似乎没有用于 dhcpcd 的脚本目录,但所有进入钩子都有一个文件,所有退出钩子都有一个文件。文件被命名为:/etc/dhcpcd.enter-hook 和 /etc/dhcpcd.exit-hook 。如果将 dhclient 钩子脚本放入这些文件中,它们无需修改即可工作。我印象深刻!)