Openstack之datapath

半兽人 发表于: 2025-09-19   最后更新时间: 2025-09-19 16:25:20  
{{totalSubscript}} 订阅, 13 游览

datapath 在 Open vSwitch(OVS)和 Linux 内核网络里是一个核心概念。我们从最基础开始,层层解释:

1. datapath 是什么

  • 字面意思:数据路径,指数据包在内核中被 OVS 处理时走的那条“管道”。
  • 在 OVS 里:datapath 就是 OVS 内核模块里的数据处理引擎。它负责 接收网卡上的数据包、匹配规则、执行动作(转发/丢弃/修改)
  • 在体系结构里

    • OVS 分两部分:

      1. 用户态 (ovs-vswitchd):管理控制层,负责和 OpenFlow、OVN、Neutron 等交互,决定策略。
      2. 内核态 (datapath):数据平面,负责真正的数据转发和包处理。
    • 简单说:datapath 就是内核里干体力活的工人,用户态是调度员

2. datapath 干什么的

它主要有几个职责:

  1. 拦截数据包

    • 网卡收到的数据包交给内核,内核把它交给 OVS datapath。
    • datapath 根据是否有匹配规则决定怎么处理。
  2. 快速转发

    • datapath 维护一个叫 flow table(流表)的缓存,类似交换机里的转发表。
    • 如果数据包匹配上了已有 flow,直接执行动作(比如转发到另一个端口)。
    • 如果没有匹配,数据包会送到用户态 ovs-vswitchd,问“这包该咋办”,用户态下发规则,datapath 更新 flow table,下次遇到类似的包就能直接走内核,不用再问。
    • 这叫 fast path(快速路径)slow path(慢速路径) 的区别。
  3. 执行动作
    datapath 能执行的操作包括:

    • 修改包头(改 MAC/IP/端口等)
    • 封装/解封装(VXLAN、GRE、Geneve)
    • 转发到某个虚拟端口或物理端口
    • 丢弃
  4. 桥接内核和用户态

    • 用户态负责“策略和规则下发”,
    • 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 showovs-dpctl dump-flows
  • 查 bridge 配置:ovs-vsctl show

OVS 和 内核

很多人一开始都会困惑:OVS 明明是一个“用户态程序”,为什么能插到内核里面,甚至能接管网卡转发?我们从原理和历史两方面来解释。

1. OVS 和内核的关系

  • OVS 不只是一个用户态程序
    OVS 的完整实现包含两部分:

    1. 内核模块(datapath) → 负责高速转发(data plane)。
    2. 用户态进程(ovs-vswitchd, ovsdb-server 等) → 负责策略控制(control plane)。
  • 为什么要内核模块?
    因为数据包的转发如果完全靠用户态,性能会非常差:

    • 每个包都要从内核态复制到用户态 → 决策 → 再复制回内核态 → 转发。
    • 这样速度就和软件路由器一样,完全无法满足万兆甚至百兆的转发要求。

    所以 OVS 在内核里写了一个 datapath 模块,直接在内核空间处理大部分数据包。
    这样转发只需内核态一次处理,不用来回切换。

2. 为什么 datapath 能“侵入”内核?

这并不是 OVS 私自“黑进去”的,而是内核官方提供的机制:

  1. Linux 内核本身允许第三方内核模块

    • 内核的设计是模块化的,任何程序都可以写一个内核模块 (.ko) 并加载到内核中。
    • openvswitch.ko 就是一个内核模块,加载后注册为内核的一个“虚拟交换机驱动”。
    • 这和网卡驱动 (ixgbe.ko, e1000.ko) 本质上是同一类东西:驱动内核如何处理数据包。
  2. 内核网络子系统是可扩展的

    • Linux 网络协议栈有很多“钩子点”(hooks),比如 Netfilter、TC、Netlink、协议栈的接收/发送路径。
    • OVS datapath 就是利用这些 hook,把数据包接收下来,然后交给自己的 flow table 来处理。
  3. 官方合并进了 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)|
   +---------------+                 +---------------+

图解说明

  1. OpenStack Neutron

    • 不直接管内核转发,而是通过 ovs-vsctl 等命令控制 ovs-vswitchd,告诉它“该建哪些桥、加哪些流表”。
  2. ovs-vswitchd(用户态)

    • 它是 OVS 的“大脑”。
    • 负责接收 OpenStack 的策略,并通过 Netlink 与内核态的 datapath 通信。
  3. OVS datapath(内核态)

    • 这是 OVS 的“心脏”。
    • 维护 flow table,负责高速转发。
    • 收到数据包时,直接查表执行动作。
    • 如果没有匹配,就上报给用户态 ovs-vswitchd,由它决定,然后写回 flow 表(slow path → fast path)。
  4. 物理网卡 / 虚拟端口

    • 物理网卡(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-intbr-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)
   │ 驱动发包
   ▼
外部主机

关键点

  1. datapath 是关键接力点:物理网卡、虚拟网卡(vnet/tap)、bridge 端口的数据都要先过 datapath。
  2. fast path / slow path

    • 匹配 flow → fast path(纯内核态转发,极快)。
    • 没匹配 → slow path(交给 ovs-vswitchd 处理,速度慢,但只发生一次)。
  3. 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 → 外部网络)

内核路径拆解

  1. 网卡驱动 → net_device

    • Linux 内核把所有网卡(物理/虚拟)抽象成 struct net_device
    • 无论是物理口(eno12399)还是虚拟口(tap/vnet0),都通过这个接口向内核提交/接收数据包。
  2. 协议栈 Hook → OVS datapath

    • openvswitch.ko 注册在 Linux 网络协议栈里。
    • 它会拦截从某些 net_device 收到的包。
    • 进入 datapath 后,走 flow table 匹配逻辑。
  3. flow table 匹配

    • 在内核态维护一个哈希表(key: 五元组+其他字段, value: 动作)。
    • 命中 → 直接执行动作(比如输出到某个 net_device)。
    • 未命中 → 通过 Netlink 把包上送到用户态 ovs-vswitchd。
  4. 用户态 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-exbr-intvnetX 等关键点。

外部 → 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 应用收到数据包 ]

图解

  1. eno12399:物理网卡收包,把数据交给内核。
  2. OVS datapath:作为内核模块,拦截并查 flow 表。
  3. br-ex:对外的网桥,负责“物理网 ↔ 虚拟网”转换。
  4. br-int:内部网桥,所有 VM 的 tap 接口都在这里。
  5. vnetX:某个 VM 的 tap 网卡,数据包送到这里,相当于进了 VM 的网口。

反方向 (VM → 外部)

路径就是倒过来:
VM eth0 → vnetX → br-int → datapath 查 flow → br-ex → datapath 查 flow → eno12399 → 外部网络。

所以核心总结:

  • datapath = 内核里的“虚拟交换芯片”,所有网桥和端口都挂在它上面。
  • br-ex:负责外部物理世界。
  • br-int:负责内部虚拟机接口。
  • flow 表 决定数据包在这些桥和端口之间怎么走。
更新于 2025-09-19
在线,11小时前登录

查看OpenStack更多相关的文章或提一个关于OpenStack的问题,也可以与我们一起分享文章