FreeBSD 中文社区 2025 第二季度问卷调查
FreeBSD 中文社区(CFC)
VitePress 镜像站QQ 群 787969044视频教程Ⅰ视频教程Ⅱ
  • FreeBSD 从入门到追忆
  • 中文期刊
  • 状态报告
  • 发行说明
  • 手册
  • 网络文章集锦
  • 笔记本支持报告
  • Port 开发者手册
  • 架构手册
  • 开发者手册
  • 中文 man 手册
  • 文章
  • 书籍
  • FreeBSD 中文期刊
  • 编辑日志
  • 2025-123 下游项目
    • FreeBSD 发布工程:新主管上任
    • GhostBSD:从易用到挣扎与重生
    • BSD Now 与将来
    • 字符设备驱动教程(第三部分)
    • 学会走路——连接 GPIO 系统
    • FreeBSD 中对 SYN 段的处理
    • FreeBSD 2024 年秋季峰会
  • 2024-1112 虚拟化
    • 字符设备驱动程序教程(第二部分)
    • 面向 Linux 和 Windows 用户的 bhyve
    • Xen 与 FreeBSD
    • Wifibox:一种嵌入式虚拟化无线路由器
    • 嵌入式 FreeBSD:Fabric——起步阶段
    • DGP:一种新的数据包控制方法
    • 会议报告:我在都柏林的 EuroBSDCon 体验
  • 2024-0910 内核开发
    • 字符设备驱动程序教程
    • VPP 移植到了 FreeBSD:基础用法
    • 利用 Kyua 的 Jail 功能提升 FreeBSD 测试套件的并行效率
    • FreeBSD 上的 Valgrind
    • 嵌入式 FreeBSD:探索 bhyve
    • TCP/IP 历险记:FreeBSD TCP 协议栈中的 Pacing
    • 实用软件:实现无纸化(Paperless)
  • 2024-0708 存储与文件系统
    • FreeBSD 中的 NVMe-oF
    • FreeBSD iSCSI 入门
    • 使用 ZFS 原生加密保护数据
    • 嵌入式 FreeBSD:打造自己的镜像
    • TCP LRO 简介
    • 基于 Samba 的时间机器备份
  • 2024-0506 配置管理对决
    • 基本系统中的 mfsBSD
    • rdist
    • Hashicorp Vault
    • 在 GitHub 上向 FreeBSD 提交 PR
    • 悼念 Mike Karels
    • 2024 年 5-6 月来信
    • 嵌入式 FreeBSD 面包板
    • TCP/IP 历险记:TCP BBLog
    • 实用软件:开发定制 Ansible 模块
  • 2024-0304 开发工作流与集成
    • FreeBSD 内核开发工作流程
    • FreeBSD 与 KDE 持续集成(CI)
    • 更现代的内核调试工具
    • 从零开始的 ZFS 镜像及 makefs -t zfs
    • 提升 Git 使用体验
  • 2024-0102 网络(十周年)
    • FreeBSD 中的 RACK 栈和替代 TCP 栈
    • FreeBSD 14 中有关 TCP 的更新
    • if_ovpn 还是 OpenVPN
    • SR-IOV 已成为 FreeBSD 的重要功能
    • FreeBSD 接口 API(IfAPI)
    • BATMAN:更优的可移动热点网络方式
    • 配置自己的 VPN——基于 FreeBSD、Wireguard、IPv6 和广告拦截
    • 实用软件:使用 Zabbix 监控主机
  • 2023-1112 FreeBSD 14.0
    • LinuxBoot:从 Linux 启动 FreeBSD
    • FreeBSD 容器镜像
    • 现在用 Webhook 触发我
    • 新的 Ports 提交者:oel Bodenmann (jbo@freebsd.org)
  • 2023-0910 Port 与软件包
    • 回忆录:与 Warner Losh(@imp)的访谈
    • 在你自己的仓库中定制 Poudriere 源
    • Wazuh 和 MITRE Caldera 在 FreeBSD Jail 中的使用
    • PEP 517
    • CCCamp 2023 旅行报告
  • 2023-0708 容器与云
    • 在 Firecracker 上的 FreeBSD
    • 使用 pot 和 nomad 管理 Jail
    • 会议报告:C 与 BSD 正如拉丁语与我们——一位神学家的旅程
    • 抒怀之旅:与 Doug Rabson 的访谈
    • 基于 Jail 的广告拦截教程
    • 我们收到的来信
  • 2023-0506 FreeBSD 三十周年纪念特刊
    • CheriBSD 近十多年的历程
    • AArch64:成为 FreeBSD 新的一级架构
    • 岁月如梭:我个人的时间线
    • 安装 FreeBSD 1.0:回顾 30 年前
    • ZFS 是如何进入 FreeBSD 的呢?
    • 我不是来自约克郡的,我保证!
    • 回忆录:采访 David Greenman Lawrence
    • FreeBSD 和早期的 Unix 社区
    • 早期的 FreeBSD 移植
    • FreeBSD 30 周年:成功的秘诀
    • FreeBSD 在日本:回忆之旅与今日之实
  • 2023-0304 嵌入式
    • CheriBSD port 和软件包
    • 让我们来试试 ChatGPT
    • GPU 直通
  • 2023-0102 构建 FreEBSD Web 服务器
    • ZFS 的原子 I/O 与 PostgreSQL
    • 虚拟实验室——BSD 编程研讨会
    • ZFS 简介
    • 会议报告:落基山庆祝女性计算机科学家
    • 进行中的工作/征求反馈:数据包批处理
    • 基金会与 FreeBSD 桌面
  • 2022-1112 可观测性和衡量标准
    • 在 FreeBSD 的 DDB 内核调试器中编写自定义命令
    • DTrace:老式跟踪系统的新扩展
    • 基于证书的 Icinga 监控
    • 活动监控脚本(activitymonitor.sh)
    • 实用 IPv6(第四部分)
    • EuroBSDCon 会议报道
    • 实用 Port:Prometheus 的安装与配置
    • 书评:《用火解决问题:管理老化的计算机系统(并为现代系统保驾护航)》Kill It with Fire: Manage Aging Computer Systems (and Future Proof Modern Ones)
  • 2022-0910 安全性
    • CARP 简介
    • 重构内核加密服务框架
    • PAM 小窍门
    • SSH 小窍门
    • 实用 IPv6(第三部分)
    • 书评:Understanding Software Dynamics(深入理解软件性能——一种动态视角)—— Richard L. Sites 著
    • 访谈:保障 FreeBSD 安全性
    • MCH 2022 会议报告
  • 2022-0708 科研、系统与 FreeBSD
    • 在 FreeBSD 上构建 Loom 框架
    • 教授本科生 Unix 课程
    • FreeBSD 入门研讨会
    • 实用 IPv6(第二部分)
    • 在 2022 年及以后推广 FreeBSD
    • 进行中的工作/征求反馈:Socket 缓冲区
    • FreeBSD 开发者峰会报告
    • 支持 Electromagnetic Field 2022
  • 2022-0506 灾难恢复
    • 使用 FreeBSD 构建高弹性的私有云
    • LLDB 14 —— FreeBSD 新调试器
    • 实用 IPv6(第一部分)
    • 利用 netdump(4) 进行事后内核调试
    • 进行中的工作/征求反馈:FreeBSD 启动性能
    • 实用 Port:在 OpenZFS 上设置 NFSv4 文件服务器
  • 2022-0304 ARM64 是一级架构
    • FreeBSD/ARM64 上的数据科学
    • Pinebook Pro 上的 FreeBSD
    • 嵌入式控制器的 ACPI 支持
    • 进行中的工作/征求反馈:Lumina 桌面征集开发人员
    • 实用 Port:如何设置 Apple 时间机器
  • 2022-0102 软件与系统管理
    • 为 FreeBSD Ports 做贡献
    • 使用 Git 贡献到 FreeBSD Ports
    • CBSD:第一部分——生产环境
    • 将 OpenBSD 的 pf syncookie 代码移植到 FreeBSD 的 pf
    • 进行中的工作/征求反馈:mkjail
    • 《编程智慧:编程鬼才的经验和思考》(The Kollected Kode Vicious)书评
    • 会议报告:EuroBSDCon 2021 我的第一次 EuroBSDCon:一位新组织者的视角
  • 2021-1112 存储
    • 开放通道 SSD
    • 构建 FreeBSD 社区
    • 与完美操作系统同行 27 年
    • 进行中的工作/征求反馈:OccamBSD
    • 通过 iSCSI 导入 ZFS ZIL——不要在工作中这样做——就像我做的那样
  • 2021-0910 FreeBSD 开发
    • FreeBSD 代码审查与 git-arc
    • 如何为 FreeBSD 实现简单的 USB 驱动程序
    • 内核开发技巧
    • 程序员编程杂谈
  • 2021-0708 桌面/无线网
    • 通往 FreeBSD 桌面的直线路径
    • FreeBSD 13 中的人机接口设备 (HID) 支持
    • Panfrost 驱动程序
    • 用 Git 更新 FreeBSD
    • FreeBSD 的新面孔
    • 想给你的桌面加点佐料?
  • 2021-0506 安全
    • 七种提升新安装 FreeBSD 安全性的方法
    • copyinout 框架
    • 使用 TLS 改善 NFS 安全性
    • Capsicum 案例研究:Got
    • 对 Jail 进行安全扫描
  • 2021-0304 FreeBSD 13.0
    • 展望未来
    • FreeBSD 13.0 工具链
    • FreeBSD 13.0 中有新加载器吗?
    • TCP Cubic 准备起飞
    • OpenZFS 中的 Zstandard 压缩
    • 会议报告:FreeBSD 供应商峰会
    • Git 不够吗?
  • 2021-0102 案例研究
    • Tarsnap 的 FreeBSD 集群
    • BALLY WULFF
    • Netflix Open Connect
    • FreeBSD 的新面孔
    • 写作学者的 FreeBSD
    • 在世界之巅
  • 2020-1112 工作流/持续集成(CI)
    • FreeBSD Git 快速入门
    • 使用 syzkaller 进行内核 Fuzzing
    • Mastering Vim Quickly 书评
    • 线上会议实用技巧
    • 在控制台上进行网络监控
  • 2020-0910 贡献与入门
    • 采访:Warner Losh,第 2 部分
    • 代码审查
    • 撰写良好的提交消息
    • 如何在不是程序员的情况下做出贡献——成为 FreeBSD 译者
    • 如何成为文档提交者
    • 谷歌编程之夏
    • 为 FreeBSD 期刊撰写文章
    • 你为什么使用 FreeBSD
    • FreeBSD 的新面孔
  • 2020-0708 基准测试/调优
    • FreeBSD Friday
    • 采访:Warner Losh,第 1 部分
    • 构建和运行开源社区
    • 在 FreeBSD 上轻松搭建我的世界(Minecraft)服务器
    • FreeBSD 的新面孔
  • 2020-0506 网络性能
    • 内核中的 TLS 卸载
    • 访谈:Michael W Lucas
    • FreeBSD 桌面发行版
    • 使用 Poudriere 进行 Port 批量管理
    • FreeBSD 的新面孔
由 GitBook 提供支持
LogoLogo

FreeBSD 中文社区(CFC) 2025

在本页
  • 问题
  • DCO 是什么
  • 考虑事项
  • 多路复用
  • UDP
  • 硬件加密卸载
  • 锁设计
  • 控制接口
  • 路由查找
  • 密钥轮换
  • vnet
  • 性能
  • 后续工作
  • 致谢
  • 脚注
在GitHub上编辑
导出为 PDF
  1. 2024-0102 网络(十周年)

if_ovpn 还是 OpenVPN

上一页FreeBSD 14 中有关 TCP 的更新下一页SR-IOV 已成为 FreeBSD 的重要功能

最后更新于22天前

  • 原文链接:

  • 作者:Kristof Provost

今天①,你将了解② OpenVPN 的 DCO(数据通道卸载)功能。

OpenVPN 最初由 James Yonan 开发,首次发布于 2001 年 5 月 13 日。它支持许多常见平台(如 FreeBSD、OpenBSD、Dragonfly、AIX 等)以及一些较为罕见的平台(如 macOS、Linux、Windows)(译者注:原文如此)。它支持点对点和客户端 - 服务器模型,并可基于预共享密钥、证书和用户名/密码进行认证。

正如你所期望的,所有存在 20 余年的项目都会在各种的使用场景下不断增长许多功能。

问题

尽管 OpenVPN 异常出色,但它也存在明显的问题。没有问题,这篇文章就不会那么有趣③。的确,有毛病,那就是 OpenVPN 单线程实现的用户空间进程。

OpenVPN 使用 if_tun 向网络栈注入数据包。因此,它的性能跟不上现今的连接速度。同时,这也使得它难以利用现代多核硬件和加密卸载硬件。

OpenVPN 性能图

OpenVPN 的主要性能问题在于它的用户空间特性。进入的流量自然会被网卡接收,网卡通常会将数据包通过 DMA 传送到内核内存。然后,这些数据包会继续被网络栈处理,直到网络栈确定数据包属于哪个套接字,并将其传到用户空间。这个套接字可能是 UDP/TCP。

将数据包传递到用户空间涉及到复制数据包,此时用户空间的 OpenVPN 进程会验证、解密数据包,然后通过 if_tun 将其重新注入到网络栈中。这意味着需要将明文数据包复制回内核进行进一步处理。

无可避免地,这种上下文切换和数据包来回复制对性能产生了明显的影响。

在当前架构下,想要显著提高性能非常困难。

DCO 是什么

既然我们已经明确了问题所在,就可以开始想想解决方案了④。

如果把问题锁定在上下文切换到用户空间,那么有一种可行的解决方案就是将工作保持在内核中,这就是 DCO(数据通道卸载)所做的。

DCO 将数据通道(即加密操作和流量隧道化)移动到内核中。它使用一款新的虚拟设备驱动程序 if_ovpn 实现。OpenVPN 用户空间进程仍然负责连接的建立(包括认证和选项协商),并通过一个新的 ioctl 接口与 if_ovpn 驱动程序进行协调。

OpenVPN 项目认为,引入 DCO 是一次极好的机会:能删除一些遗留功能,进行一些清理。在这方面,他们采取了 Henry Ford 在加密算法选择上的方法——你可以选择任何加密算法,只要你选择 AES-GCM 和 ChaCha20/Poly1305,且都使用黑色(即未压缩)。此外,DCO 还不支持压缩、第二层流量、非子网拓扑和流量整形⑤。

值得注意的是,DCO 并不会改变 OpenVPN 协议。客户端可以与不支持 DCO 的服务器一起使用,反之亦然。当然,当双方都使用 DCO 时,你能获得最大的好处,但这不是强制要求的。

考虑事项

在这一部分,我将讨论这一切有多么困难,以便让你们对我能够成功实现这一功能留下深刻印象。如果我告诉你我正在这么做,这个方式还有效吗?让我们试试看吧!

不管怎样,有几个方面需要特别关注:

多路复用

第一个问题是 OpenVPN 使用单一连接来传输隧道数据和控制数据。隧道数据需要由内核处理,而控制数据则由 OpenVPN 用户空间进程处理。

你能看到这个问题。套接字最初是由 OpenVPN 自身完全拥有的。它设置隧道并处理认证。完成后,它会部分地将控制权交给内核端(即 if_ovpn)。

这意味着需要通知 if_ovpn 文件描述符(内核用来查找内核中的 struct socket),以便它可以持有该引用。这样可以确保套接字在内核使用时不会消失,可能因为 OpenVPN 进程被终止,或因为它遇到问题决定捣乱。毕竟它是在用户空间,可能会做一些疯狂的事情。

函数 ovpn_udp_input() 是接收路径的主要入口点。网络栈会将到达该套接字的所有 UDP 数据包交给此函数处理。

函数首先检查数据包是否能由内核驱动处理。也就是说,数据包是数据包并且目标是已知的对等体。如果不是这种情况,过滤函数会告诉 UDP 代码按正常流程传递数据包,仿佛没有过滤函数一样。这样,数据包就会到达套接字,并由 OpenVPN 的用户空间进程进行处理。

早期版本的 DCO 驱动有单独的命令 ioctl 来读取和写入控制消息,但 Linux 和 FreeBSD 的驱动都已适配为使用套接字。这简化了控制数据包和新客户端的处理。

另一方面,如果数据包是已知对等体的数据包,它会被解密,验证其签名,然后传递给网络栈进行进一步处理。

UDP

OpenVPN 能通过 UDP 和 TCP 运行。虽然 UDP 是层 3 VPN 协议的优选,但某些用户需要通过 TCP 运行它以便穿越防火墙。

FreeBSD 内核提供了一项方便的 UDP 套接字过滤功能,但 TCP 没有类似的功能,因此 FreeBSD 的 if_ovpn 当前仅支持 UDP,不支持 TCP。

Linux 的 DCO 驱动开发者则更加激进,选择实现了对 TCP 的支持。开发者虽然面临重重挑战,但最终还是成功地完成了这一任务,现在他的经验大为增加。

硬件加密卸载

if_ovpn 依赖于内核中的 OpenCrypto 框架进行加密操作。这意味着它还可以利用系统中存在的任何加密卸载硬件,从而进一步提高性能。

它已经通过英特尔的 QuickAssist 技术(QAT)、SafeXcel EIP-97 加密加速器和 AES-NI 进行过测试。

锁设计

看,如果你以为你可以在不讨论锁的情况下阅读内核代码,我真不知道该怎么告诉你。那的确是过于天真的乐观了。

几乎每款现代 CPU 都有多个核心,而能够使用不止一个核心自然是很有意义的。也就是说,我们不能在一个核心执行工作时,锁住其他核心。这不太礼貌,性能表现也不会太好。

幸运的是,这个问题的解决办法相对简单。整个方法基于区分对 if_ovpn 内部数据结构的读取和写入操作。也就是说,我们能让多个核心同时查找数据,但每次只有一个核心可以修改数据(并且在修改时不允许有其他核心读取)。这种方法足够有效,因为——大部分时间——我们并不需要修改数据。

常见的情况是,当我们接收或发送数据包时,只需要查找密钥、目标地址、端口和其他相关信息。

仅在我们修改数据时(即在配置更改或重新密钥时),我们才需要获取写锁,并暂停数据通道。这个过程足够短促,我们这些微不足道的人类大脑几乎不会察觉到,这也让大家都感到高兴。

控制接口

每款平台的 OpenVPN DCO 都有自己独特的方式来实现用户空间 OpenVPN 和内核模块之间的通信。

在 Linux 上,通过 netlink 完成,但 if_ovpn 的工作在 FreeBSD 的 netlink 实现完成之前就已经完成。由于我仍然在为上次的因果关系违规而接受观察期,我决定使用其他方法。

这些调用将一个 ifdrv 结构传递给内核。字段 ifd_cmd 用于传递命令,而字段 ifd_data 和 ifd_len 用于在内核和用户空间之间传递特定于设备的结构。

在某种程度上,if_ovpn 偏离了传统的方法,它传输的是序列化的 nvlists,而非结构体。这使得扩展接口更加容易。或者说,它意味着我们可以在不破坏现有用户空间消费者的情况下扩展接口。如果在结构体中添加一个新字段,它的布局会发生变化,这要么意味着现有代码由于大小不匹配⑦拒绝接受它,要么就会感到非常困惑,因为字段的意义不再是原来的那样。

序列化的 nvlists 允许我们添加字段,而不会混淆另一方。任何未知的字段将被忽略。这使得添加新功能变得更加容易。

路由查找

你可能认为 if_ovpn 不需要担心路由决策。毕竟,内核的网络栈在数据包到达网络驱动程序时已经做出了路由决策。你错了。我本来想取笑你,但我也花了一些时间才弄明白这一点。

问题在于,在一个给定的接口 if_ovpn 上,可能存在多个对等体(例如,当它作为服务器并有多个客户端时)。内核已经确定数据包需要发送给其中的某个对等体,但内核假设这些客户端都在同一个广播域中。也就是说,发送到该接口的数据包将对所有客户端可见。然而,在这里并非如此,因此 if_ovpn 需要确定数据包应该发送给哪个客户端。

只有当 if_ovpn 确定了数据包应该发送给哪个对等体时,数据包才会被加密并传输。

密钥轮换

OpenVPN 会定期更换用于加密隧道的密钥。这是一个由 if_ovpn 留给用户空间来处理的难题,因此 OpenVPN 和 if_ovpn 之间需要进行一些协调。

OpenVPN 会通过 OVPN_NEW_KEY 命令安装新密钥。每个密钥都有一个 ID,且每个数据包中都包含用于加密它的密钥 ID。这意味着,在密钥轮换期间,所有数据包仍然可以解密,因为旧的和新的密钥都会在内核中保持活动状态。

若新密钥安装完成,它可以通过命令 OVPN_SWAP_KEYS 使其生效。也就是说,新的密钥将用于加密即将发送的数据包。

稍后,旧密钥可以通过命令 OVPN_DEL_KEY 删除。

vnet

是的,我们不得不谈一下 vnet。既然是我写的,避不开这个话题。

我懒得从头解释 vnet,所以我只给你推荐一篇更好的文章,作者是 Olivier Cochard-Labbé:“Jail: vnet by examples”⑧。

你可以把 vnet 看作是将 Jail 转变为拥有自己 IP 栈的虚拟机。

这在 pfSense 的使用场景下不是严格要求的,但它使测试变得更简单得多。这样,我们可以在单台机器上进行测试,而不需要任何外部工具(除了 OpenVPN 本身,这点应该很明显)。

性能

在经历了这一切之后,我敢打赌你在问自己:“这真的有好处吗?”

幸运的是,对我来说:是的,确实有好处。

我在 Netgate 的一位同事花了一些时间用 iperf3 对 Netgate 4100⑩ 设备进行测试,并得到了以下结果:

测试类型
吞吐量

if_tun

207.3 Mbit/s

DCO Software

213.1 Mbit/s

DCO AES-NI

751.2 Mbit/s

DCO QAT

1,064.8 Mbit/s

“if_tun”是旧的 OpenVPN 方法,无 DCO。值得注意的是,它在用户空间使用了 AES-NI 指令,而 "DCO Software" 设置则没有。尽管有明显的作弊行为,DCO 仍然略快。在公平的条件下(即 DCO 确实使用 AES-NI 指令),差距更是显而易见,DCO 的速度是原来的三倍多。

对于英特尔来说,还有好消息:他们的 QuickAssist 卸载引擎比 AES-NI 更快,使得 OpenVPN 的速度是以前的五倍。

后续工作

没有什么是完美的,总有改进的空间,但在某些方面,接下来的这一增强功能正是 DCO 设计成功的结果。OpenVPN 的协议使用了 32 位初始化向量(IV),出于加密原因,我在这里不再解释⑪,重复使用相同密钥的 IV 是不安全的。

这意味着必须在达到这一点之前重新协商密钥。OpenVPN 的默认重新协商间隔是 3600 秒,假设有 30% 的安全余地,这将相当于 2^32 * 0.7 / 3600,即每秒约 835,000 个数据包。这个速度大约是 8 到 9 Gbit/s(假设 1300 字节的数据包)。

对于 DCO 来说,这已经差不多可以被现代硬件所支持了。

虽然这是个好问题,但依然是个问题,因此 OpenVPN 开发人员正在开发一种更新的包格式,使用 64 位 IV。

致谢

if_ovpn 的工作得到了 Rubicon Communications(以 Netgate 名义运营)的资助,用于 pfSense 产品线。从 22.05 版本的 pfSense Plus 发布⑫以来,它一直在该平台上使用。此工作已上游合并到 FreeBSD,并成为最近的 14.0 版本的一部分。使用该功能需要 OpenVPN 2.6.0 及更高版本。

我还要感谢 OpenVPN 的开发者们,在初始的 FreeBSD 补丁出现时,他们非常热情,还提供了帮助,没有他们的协助,这个项目不会像现在这样顺利进行。

脚注

  1. 或者是你阅读这篇文章的时候。

  2. 好吧,写作。阅读。看,如果你要对这点吹毛求疵,我们会一直讨论下去。

  3. 看,如果你对 DCO 不感兴趣,你可以直接去阅读下一篇文章。我敢肯定那篇文章会很不错。

  4. 我说“我们”,但尽管我很想为这个解决方案归功于自己,实际上是 OpenVPN 的开发者们设计了 DCO 架构并实现了 Windows 和 Linux 的版本。我做的只是他们做的事情,但为 FreeBSD 做的。

  5. 在 OpenVPN 中,DCO 可以与操作系统的流量整形(即 dummynet)结合使用。

  6. 你也许可以说因为结构体变得臃肿了。你可能会这么说,但我太客气,不这么说。

  7. (主要因为我自己也不懂它们。)


Kristof Provost 是一名自由职业的嵌入式软件工程师,专注于网络和视频应用。他是 FreeBSD 的提交者,负责维护 FreeBSD 中的 pf 防火墙。目前,他大部分时间都在为 Netgate 的 pfSense 项目工作。

Kristof 总是不小心碰到 uClibc 的 bug,而且对 FTP 恨之入骨。千万不要和他谈 IPv6 分片的问题。

DCO 架构图

对于那些想要跟踪内核代码的朋友,你可以关注函数 ⑥。

通过查找套接字后,我们现在还可以通过 安装过滤函数。该过滤器 检查所有传入的数据包,决定它是有效负载数据包,应该由内核处理,还是控制数据包,应该由 OpenVPN 用户空间进程处理。

这个隧道功能也是我对其余网络栈做出的唯一更改。需要让它知道某些数据包应该由内核处理,而其他数据包仍然可以传递到用户空间。相关修改已在中完成。

对于那些跟踪代码的朋友,相关处理代码在。

有一个例外是“我们不会修改处理数据”这个规则,那就是数据包计数器。每个数据包都会被计数(甚至两次,一次是数据包计数,另一次是字节计数),这必须并发进行。幸运的是,内核的框架 正好为这种情况而设计。它为每个 CPU 核心保留总计,以确保一个核心不会影响或拖慢其他核心。仅在读取计数器时,内核才会向每个核心请求其总计并将它们加总。

通过现有的 ioctl 接口路径对 if_ovpn 驱动进行配置。具体来说,就是调用 。

这通过函数 处理。该函数首先查看对等体列表,检查是否有对等体的 VPN 地址与目标地址匹配(通过 和 ,具体取决于地址族)。如果找到匹配的对等体,数据包就会发送给该对等体。如果没有找到,ovpn_route_peer() 会执行一次路由查找,并用结果网关地址再次进行对等体查找。

对于有兴趣了解具体操作的人,还有另一篇可能有用的 文章:《The Automated Testing Framework》⑨,哦等等,我好像知道那个人,Kristof Provost。

*

ovpn_new_peer()
udp_set_kernel_tunneling()
ovpn_udp_input()
这个提交
这里
counter(9)
SIOCSDRVSPEC/SIOCGDRVSPEC
ovpn_route_peer()
ovpn_find_peer_by_ip()
ovpn_find_peer_by_ip6()
FreeBSD Journal
查看代码:
Jail: vnet by examples
The Automated Testing Framework
Netgate 4100
pfSense Plus 软件版本 22.05 已发布
if_ovpn or OpenVPN