在作为 vpn 隧道的 udp 连接上实现 pmtu 发现

在作为 vpn 隧道的 udp 连接上实现 pmtu 发现

我以编程方式创建了一个套接字,该套接字绑定到虚拟接口,并根据默认路由表规则设置接收所有传出流量。一旦传出数据包到达,它将被封装一些 VPN 标头并通过物理接口发送到远程隧道网关。

我想知道是否可以对隧道网关实现任何类型的路径 mtu 发现算法,以避免数据包碎片并提高性能。

我想到的一个解决方案是为一些随机传出的数据包设置 IP 标头中的 DF 位,并捕获具有以下标头的任何 icmp 响应:

Type: 3 (Destination Unreachable)
Code: 4 (Fragmentation Needed and Don't Fragment was Set)

然后我保持响应长度并发送减小大小的 icmp 数据包,直到达到 DF=1 的最大数据包大小并获得成功响应。

我想知道是否有更好的方法来做到这一点..也许使用一些内置机制?

也许以下设置会自动执行此操作(net.inet.tcp.path_mtu_discovery)?如果没有,有没有办法从路由表缓存中读取它?

谢谢 !

答案1

我想知道是否有更好的方法来做到这一点。

设置 DF 为全部数据包,而不仅仅是随机数据包。(请记住,“路径 MTU”意味着每条路径可能有自己的 MTU – 到节点 B 的 MTU 可能是 1500,但到节点 C 的 MTU 可能是 1280。)

也许使用一些内置机制?

通常内置的机制。对于 TCP,它内置于操作系统的 TCP 实现中;当您在 UDP 之上构建时,您基本上是在实现自己的传输协议,因此处理 MTU 发现也成为您的工作。

设置 IP_MTU_DISCOVER 套接字选项(用于设置 DF 位的选项)时,Linux 本身将读取 ICMP“太大”响应并更新其路由缓存。如 ip(7) 手册中 IP_MTU_DISCOVER 下所述,您可以使用 getsockopt(IP_MTU) 检索 MTU,而无需自己解析 ICMP。

有没有办法从路由表缓存中读取它?

创建一个 UDP 套接字,将其 connect() 到端点地址,然后使用 getsockopt(IP_MTU) 检索路径 MTU——在 ip(7) 手册的 IP_MTU_DISCOVER 中也有提及。


最后,请记住,并非所有路由器都能正确生成 ICMP“太大”,也并非所有防火墙都允许此类数据包通过,因此,仅依靠 IP 级 PMTUD 显然是不够的 - 您很可能还需要实现更高层的机制。例如,TCP(至少在 Linux 上)在 sysctl 下实现自己的 MTU 发现net.ipv4.tcp_mtu_probing;每当大型 TCP 段无法传送时,都会使用此功能。

相关内容