datapath 在 Open vSwitch(OVS)和 Linux 内核网络里是一个核心概念。我们从最基础开始,层层解释:
1. datapath 是什么
- 字面意思:数据路径,指数据包在内核中被 OVS 处理时走的那条“管道”。
- 在 OVS 里:datapath 就是 OVS 内核模块里的数据处理引擎。它负责 接收网卡上的数据包、匹配规则、执行动作(转发/丢弃/修改)。
在体系结构里:
OVS 分两部分:
- 用户态 (ovs-vswitchd):管理控制层,负责和 OpenFlow、OVN、Neutron 等交互,决定策略。
- 内核态 (datapath):数据平面,负责真正的数据转发和包处理。
- 简单说:datapath 就是内核里干体力活的工人,用户态是调度员。
2. datapath 干什么的
它主要有几个职责:
拦截数据包
- 网卡收到的数据包交给内核,内核把它交给 OVS datapath。
- datapath 根据是否有匹配规则决定怎么处理。
快速转发
- datapath 维护一个叫 flow table(流表)的缓存,类似交换机里的转发表。
- 如果数据包匹配上了已有 flow,直接执行动作(比如转发到另一个端口)。
- 如果没有匹配,数据包会送到用户态 ovs-vswitchd,问“这包该咋办”,用户态下发规则,datapath 更新 flow table,下次遇到类似的包就能直接走内核,不用再问。
- 这叫 fast path(快速路径) 和 slow path(慢速路径) 的区别。
执行动作
datapath 能执行的操作包括:- 修改包头(改 MAC/IP/端口等)
- 封装/解封装(VXLAN、GRE、Geneve)
- 转发到某个虚拟端口或物理端口
- 丢弃
桥接内核和用户态
- 用户态负责“策略和规则下发”,
- datapath 负责“数据的执行和转发”。
- 两者之间通过 Netlink 通信。
3. datapath 在网络里的位置
你可以这样理解整个过程:
物理网卡(eno12399) 收到数据包 → 内核驱动 → datapath 拦截 → 查 flow 表 →
- 有规则:直接转发到 br-ex(OVS bridge 里的虚拟端口)。
- 没规则:送去 ovs-vswitchd,请求策略,然后下发规则,更新 datapath。
所以 datapath 就是为什么你的物理网卡能把包“直接给 br-ex”的关键:
- 因为内核里 OVS 的 datapath 已经接管了这张网卡(通过
ovs-vsctl add-port br-ex eno12399
)。 - 网卡驱动收到包 → 内核调用 datapath → datapath 决定交给哪个 bridge 端口。
4. 总结类比
如果把 OVS 看成“一个虚拟交换机”:
- ovs-vswitchd(用户态):交换机的大脑,负责学习和下发规则。
- datapath(内核态):交换机的背板,负责高速搬运电信号(数据包)。
要验证 datapath 的存在和工作情况,可以:
- 看 OVS 内核模块:
lsmod | grep openvswitch
- 查 flow 表:
ovs-dpctl show
、ovs-dpctl dump-flows
- 查 bridge 配置:
ovs-vsctl show
OVS 和 内核
很多人一开始都会困惑:OVS 明明是一个“用户态程序”,为什么能插到内核里面,甚至能接管网卡转发?我们从原理和历史两方面来解释。
1. OVS 和内核的关系
OVS 不只是一个用户态程序。
OVS 的完整实现包含两部分:- 内核模块(datapath) → 负责高速转发(data plane)。
- 用户态进程(ovs-vswitchd, ovsdb-server 等) → 负责策略控制(control plane)。
为什么要内核模块?
因为数据包的转发如果完全靠用户态,性能会非常差:- 每个包都要从内核态复制到用户态 → 决策 → 再复制回内核态 → 转发。
- 这样速度就和软件路由器一样,完全无法满足万兆甚至百兆的转发要求。
所以 OVS 在内核里写了一个 datapath 模块,直接在内核空间处理大部分数据包。
这样转发只需内核态一次处理,不用来回切换。
2. 为什么 datapath 能“侵入”内核?
这并不是 OVS 私自“黑进去”的,而是内核官方提供的机制:
Linux 内核本身允许第三方内核模块
- 内核的设计是模块化的,任何程序都可以写一个内核模块 (
.ko
) 并加载到内核中。 - openvswitch.ko 就是一个内核模块,加载后注册为内核的一个“虚拟交换机驱动”。
- 这和网卡驱动 (
ixgbe.ko
,e1000.ko
) 本质上是同一类东西:驱动内核如何处理数据包。
- 内核的设计是模块化的,任何程序都可以写一个内核模块 (
内核网络子系统是可扩展的
- Linux 网络协议栈有很多“钩子点”(hooks),比如 Netfilter、TC、Netlink、协议栈的接收/发送路径。
- OVS datapath 就是利用这些 hook,把数据包接收下来,然后交给自己的 flow table 来处理。
官方合并进了 Linux 主线内核
- OVS 最早(2009 年)是一个独立的项目。
- 2012 年,OVS datapath 被正式合并进 Linux 内核主线(3.3 版本)。
- 所以现在 OVS 并不是“私自侵入内核”,而是 Linux 内核自带支持 的一种虚拟交换机实现。
- 也就是说,内核功能里天然就有 datapath,用户态 ovs-vswitchd 只是利用它。
3. OVS vs OpenStack 的关系
你提到的“ovs 不是 openstack 自己实现的一个程序嘛”这个是一个常见误区:
- OVS 不是 OpenStack 写的,它是一个独立的开源项目(最早由 Nicira 公司开发,后来被 VMware 收购)。
- OpenStack Neutron(网络组件)只是用 OVS 来做底层虚拟交换机。
- 所以 OpenStack 调用 OVS,但 OVS 本身远比 OpenStack 历史久、功能独立。
4. 为什么 datapath 能维护 flow?
因为 datapath 就是一个内核里的虚拟交换机实现,它在内核里有独立的 flow table 结构。
flow table 在内核里:
- 当数据包进入 datapath 时,先查 flow table(哈希表)。
- 如果命中,直接按 action 转发。
- 如果没命中,就上报给用户态 ovs-vswitchd,由它决定怎么处理,再把结果写回内核 flow table。
这种设计就是 内核负责 fast path,用户态负责 slow path,完全模仿硬件交换机 ASIC 的架构。
5. 总结类比
可以这样打比方:
- Linux 内核就像一个“工厂”,允许别人接插设备。
- OVS datapath 就是一个“插件设备”,插进内核后,替代默认的转发逻辑来处理数据包。
- OpenStack 只是这个“工厂”的客户,它调用 OVS,但不拥有 OVS。
所以答案是:
- datapath 能在内核里工作,是因为 Linux 内核支持可加载模块机制。
- OVS datapath 早已合并进 Linux 内核主线,是官方认可的功能,不是“强行侵入”。
- 它之所以能改变转发,是因为它注册成了内核里的虚拟交换机驱动,掌控了网卡和虚拟端口的数据路径。
要不要我帮你画一张 OVS 内核与用户态交互架构图?这样你就能直观看到 datapath 在内核里的位置,以及它和 ovs-vswitchd、OpenStack 的关系。
好,那我帮你画一个 OVS 架构图,重点突出 datapath 在内核里的角色,以及它和用户态 / OpenStack 的关系。
+----------------------+
| OpenStack |
| (Neutron ML2等) |
+----------+-----------+
|
v
+----------------------+
| ovs-vswitchd | ← 用户态控制进程
| (Control Plane) |
+----------+-----------+
| Netlink
v
============================================================
Linux 内核空间 (Data Plane)
============================================================
^
+----------+-----------+
| OVS datapath | ← 内核模块 (openvswitch.ko)
| (flow table, actions)|
+----------+-----------+
^
+---------------+-----------------+
| |
+-------+-------+ +-------+-------+
| 物理网卡 | | 虚拟端口/TAP |
| (eno12399等) | | (VM接口 vnetX)|
+---------------+ +---------------+
图解说明
OpenStack Neutron
- 不直接管内核转发,而是通过
ovs-vsctl
等命令控制 ovs-vswitchd,告诉它“该建哪些桥、加哪些流表”。
- 不直接管内核转发,而是通过
ovs-vswitchd(用户态)
- 它是 OVS 的“大脑”。
- 负责接收 OpenStack 的策略,并通过 Netlink 与内核态的 datapath 通信。
OVS datapath(内核态)
- 这是 OVS 的“心脏”。
- 维护 flow table,负责高速转发。
- 收到数据包时,直接查表执行动作。
- 如果没有匹配,就上报给用户态 ovs-vswitchd,由它决定,然后写回 flow 表(slow path → fast path)。
物理网卡 / 虚拟端口
- 物理网卡(eno12399)作为 OVS bridge 的一个端口接入 datapath。
- VM 的虚拟接口(tap/vnet)也是一个 OVS 端口。
- datapath 在它们之间做转发,就像一个真实交换机。
这样你就能直观理解:
- datapath 并不是偷偷“侵入”内核,而是作为 内核模块 正式挂在网络栈里的。
- 它接管了物理网卡/虚拟网卡的数据路径,所以才能“维护 flow 表”和“决定转发”。
- 用户态只是控制器,大部分高速转发都在内核 datapath 里完成。
数据包收发路径时序图
数据包收发路径 的时序图?比如“外部请求进入 eno12399 → datapath → br-ex → 虚拟机 vnet0”的全过程。
场景:外部主机访问虚拟机
(外部主机 → 物理网卡 eno12399 → OVS bridge br-ex → 内核 datapath → tap/vnetX → 虚拟机)
外部主机
│
│ 数据包 (dst=VM_IP)
▼
物理网卡 (eno12399)
│ 驱动收包
▼
Linux 内核
│
│ 交给 OVS datapath (openvswitch.ko)
▼
OVS datapath (flow table)
│
│ 查表:
│ - 如果有匹配 → 执行动作 (比如输出到 vnetX)
│ - 如果没有匹配 → 上报 ovs-vswitchd (用户态),请求安装 flow
▼
输出到 vnetX (虚拟端口,挂在 br-int 或 br-ex 上)
│
│ 数据包进入 VM 的 tap 接口
▼
虚拟机 (eth0)
│
│ 应用程序收到数据包
▼
处理完成
反向:虚拟机访问外部主机
(VM → vnetX → OVS datapath → flow table → br-ex → 物理网卡 → 外部主机)
虚拟机 (eth0)
│
│ 应用程序发包
▼
tap/vnetX
│
│ 把包交给 OVS datapath
▼
OVS datapath (flow table)
│
│ 查表:
│ - 如果有匹配 → 执行动作 (比如输出到 eno12399)
│ - 如果没有匹配 → 上报 ovs-vswitchd,安装 flow
▼
物理网卡 (eno12399)
│ 驱动发包
▼
外部主机
关键点
- datapath 是关键接力点:物理网卡、虚拟网卡(vnet/tap)、bridge 端口的数据都要先过 datapath。
fast path / slow path:
- 匹配 flow → fast path(纯内核态转发,极快)。
- 没匹配 → slow path(交给 ovs-vswitchd 处理,速度慢,但只发生一次)。
br-ex / br-int 的作用:
- br-ex:通常接物理网卡(外网通信)。
- br-int:通常接虚拟机 vnet/tap(内网通信)。
- datapath 负责桥接它们。
换句话说:
- 物理网卡 → datapath → flow 表决策 → 虚拟机 tap
- 虚拟机 tap → datapath → flow 表决策 → 物理网卡
这就是 OVS datapath 在内核里“劫持”并加速转发的完整逻辑。
Linux 内核调用路径图
更底层的 Linux 内核调用路径图?比如 net_device → datapath hook → flow table → net_device
,这样能看清它是怎么嵌在内核网络栈里的。
重点展示 OVS datapath 是怎么嵌进内核网络栈里的。
场景:数据包从物理网卡进入 OVS
外部数据包
│
▼
[ 网卡硬件收包 ]
│
▼
[ 网卡驱动 (ixgbe/e1000 等) ]
│
▼
[ net_device 接口 (Linux 内核统一抽象) ]
│
▼
==== Linux 网络协议栈 Hook ====
│
▼
[ OVS datapath (openvswitch.ko) ]
│
│ 查 flow table:
│ - 命中 → 执行动作 (转发/修改/丢弃)
│ - 未命中 → 通过 Netlink 通知 ovs-vswitchd
▼
[ net_device 输出 ]
│
├──> 虚拟网卡 (tap/vnetX → 虚拟机)
│
└──> 物理网卡 (eno12399 → 外部网络)
内核路径拆解
网卡驱动 → net_device
- Linux 内核把所有网卡(物理/虚拟)抽象成
struct net_device
。 - 无论是物理口(eno12399)还是虚拟口(tap/vnet0),都通过这个接口向内核提交/接收数据包。
- Linux 内核把所有网卡(物理/虚拟)抽象成
协议栈 Hook → OVS datapath
- openvswitch.ko 注册在 Linux 网络协议栈里。
- 它会拦截从某些 net_device 收到的包。
- 进入 datapath 后,走 flow table 匹配逻辑。
flow table 匹配
- 在内核态维护一个哈希表(key: 五元组+其他字段, value: 动作)。
- 命中 → 直接执行动作(比如输出到某个 net_device)。
- 未命中 → 通过 Netlink 把包上送到用户态 ovs-vswitchd。
用户态 ovs-vswitchd 回应
- 决定这类包的处理策略(比如“发到 vnetX”)。
- 把 flow 下发到内核 datapath。
- 下次类似的包就能直接走 fast path。
总结类比
- Linux 内核原生有“高速公路”(网络协议栈)。
- OVS datapath 就是一个“收费站”插件,插进高速公路的入口处,检查每辆车(数据包),决定让它走哪条路。
- 收费站(datapath)大多数时候直接放行(fast path),偶尔遇到陌生车就打电话问调度员(ovs-vswitchd)。
没有 OVS vs 有 OVS
对比图:没有 OVS vs 有 OVS,这样能清楚看到 datapath 是怎么改变 Linux 默认转发流程的。
- 没有 OVS:包进来后,走默认 Linux 协议栈(IP 路由表、iptables 之类)。
- 有 OVS:包进来后,先进 OVS datapath,看 flow 表 → 再决定走向。
对比图:无 OVS vs 有 OVS
情况一:没有 OVS
====================
[ 物理网卡 eno12399 ]
│
▼
[ 内核 net_device ]
│
▼
[ Linux 协议栈 ]
- ARP
- 路由表 (ip route)
- iptables/nftables
│
▼
[ 输出网卡 (物理 or 虚拟) ]
│
▼
[ 外部网络 / 虚拟机 ]
情况二:有 OVS (datapath)
====================
[ 物理网卡 eno12399 ]
│
▼
[ 内核 net_device ]
│
▼
[ OVS datapath (openvswitch.ko) ]
- flow table 查找
- 命中 → 直接执行动作 (转发/改包/丢弃)
- 未命中 → 上报 ovs-vswitchd (用户态),安装新 flow
│
▼
[ 输出端口 (vnetX / br-ex / 物理网卡) ]
│
▼
[ 外部网络 / 虚拟机 ]
关键区别
无 OVS:
内核完全按 路由表 / iptables 决定路径。转发逻辑比较固定。有 OVS:
内核协议栈转发逻辑被 datapath 接管。- 它自己维护一份 flow 表。
- 能做比路由表更灵活的操作,比如:隧道封装 (VXLAN)、桥接不同 namespace、改 VLAN tag 等。
- 这就是 OpenStack、K8s 这些虚拟化/云平台喜欢用 OVS 的原因:它能把物理网、虚拟网、overlay 隧道揉在一起。
有 OVS 时,外部包进入 VM 的完整路径示意
外部数据包进入 VM 的完整路径(有 OVS 时),把 br-ex
、br-int
、vnetX
等关键点。
外部 → VM 路径 (典型 OpenStack 场景)
[ 外部主机 ]
│
▼
[ 物理网卡 eno12399 ]
│ (驱动收包)
▼
[ 内核 net_device ]
│
▼
[ OVS datapath (openvswitch.ko) ]
│
│ flow table 查找:
│ - 从物理口进来 → 应该交给 br-ex
▼
[ br-ex (OVS bridge) ]
│
│ flow 规则:包要转发到 br-int
▼
[ OVS datapath 继续处理 ]
│
▼
[ br-int (OVS bridge) ]
│
│ flow 规则:根据 VM 的 MAC/IP
│ → 找到对应的虚拟端口 vnetX
▼
[ vnetX (tap 设备,挂在 VM 上) ]
│
▼
[ 虚拟机 eth0 ]
│
▼
[ VM 应用收到数据包 ]
图解
- eno12399:物理网卡收包,把数据交给内核。
- OVS datapath:作为内核模块,拦截并查 flow 表。
- br-ex:对外的网桥,负责“物理网 ↔ 虚拟网”转换。
- br-int:内部网桥,所有 VM 的 tap 接口都在这里。
- vnetX:某个 VM 的 tap 网卡,数据包送到这里,相当于进了 VM 的网口。
反方向 (VM → 外部)
路径就是倒过来:
VM eth0 → vnetX → br-int → datapath 查 flow → br-ex → datapath 查 flow → eno12399 → 外部网络。
所以核心总结:
- datapath = 内核里的“虚拟交换芯片”,所有网桥和端口都挂在它上面。
- br-ex:负责外部物理世界。
- br-int:负责内部虚拟机接口。
- flow 表 决定数据包在这些桥和端口之间怎么走。