OVS源码入门:从流表匹配到datapath内核转发原理
简介本资源是一份面向SDN初学者与网络开发者的Open vSwitch源码深度解析笔记聚焦OVS核心机制与OpenFlow协议实现原理。内容系统梳理了OVS网络架构ovs-vswitchd、ovsdb-server等组件协同关系、内部模块分层ofproto抽象层、ofproto-dpif实现、netdev设备抽象及关键代码路径尤其深入剖析datapath内核模块的初始化流程、收包处理链路netdev_frame_hook→ovs_dp_process_packet、流表哈希桶结构与创建逻辑alloc_buckets、dp_flow_genl_ops辅以清晰的数据流向图示与关键函数调用分析。资源为单文件PDF大小1012KB内容覆盖2.3.90版本源码适合作为阅读OVS源码的入门指南与调试参考。目前已有977人学习下载笔记结构完整、术语准确、注释详实能有效帮助读者建立OVS用户态与内核态协同工作的整体认知并快速定位关键模块源码位置与执行逻辑。1. 别被“源码阅读笔记”吓住它其实是一张 OVS 的「地铁线路图」专治看不懂虚拟交换机的焦虑你刚点开这份《Openvswitch源码阅读笔记.pdf》看到满屏的ovs_dp_process_packet()、ofproto_dpif_class、sw_flow_key……第一反应是不是这哪是笔记这是天书别急——这恰恰说明你不是一个人。我第一次打开它时也盯着第3页那个“datapath 流表哈希桶”的 flex_array 结构图发了15分钟呆心想“我连 OVS 是干啥的都没整明白现在就要看内核模块怎么分页存流表”其实这份笔记根本不是让你从头逐行背代码的“考试大纲”而是一份给新手画的 OVS 运行地图它不讲所有函数怎么写但清楚标出了——数据包从网卡进来经过哪几道门vport → key 提取 → 流表匹配 → action 执行哪扇门走不通会拐去用户态upcall哪条路是控制器远程按下的开关OpenFlow flow_mod。它把一个庞大、分层、横跨内核/用户态的虚拟交换系统拆成了你能摸得着的“入口→中转站→出口”链条。适合谁就是你现在这个状态的人听说过 SDN、OpenFlow、OVS知道它们和“云网络”“虚拟机互通”有关但一查资料就掉进术语坑里——“ofproto 是什么”“dpif 和 netdev 有啥区别”“为什么流表要搞 hash 桶还带 mask cache”……这份笔记就是专门帮你把脚从坑里拔出来踩在第一个可理解的台阶上。它不承诺让你三天写出 patch但能保证你读完第5页再看到ovs-ofctl add-flow命令时脑子里浮现的不再是黑盒子而是一段真实跑在内存里的逻辑哦原来这条命令最终是调到了ovs_flow_cmd_new()往内核datapath的哈希桶里塞了一个新sw_flow结构体。这就是它的价值把玄学变常识把黑匣子变透明管道。接下来我们就按这张地图从最外层的“OVS 是什么”开始一层层剥开直到亲手跑通第一个流表匹配实验。2. 先搞懂一个概念OVS 不是“软件交换机”而是 SDN 架构里那个「听指挥的执行员」很多新手入门第一步就卡住了为什么非得学 OVSDocker 自带 bridge 不也能连容器吗Kubernetes 的 CNI 插件不也管网络吗这里必须先划清一条线——OVS 的核心身份不是“多了一个交换功能”而是SDN软件定义网络落地的关键执行层。它存在的唯一目的就是把远端控制器Controller发来的抽象策略变成 Linux 内核里真实转发数据包的动作。我们用一个生活化类比来破冰想象一座智能大厦的消防系统。传统网络就像每层楼自己装独立烟雾报警器A 层起火A 层警报响B 层完全不知情更别说联动喷淋或疏散广播。而 SDN 就是给整栋楼装了一个中央消防控制室。OVS就是安装在每一层电梯口、走廊尽头、机房门口的那些“智能消防阀”。它本身不决定“哪里起火该关哪扇门”但它绝对服从控制室的指令控制室说“A 区通道关闭、B 区喷淋启动”OVS 就立刻执行控制室说“临时加一条应急逃生路径”OVS 就马上在流表里加一条新规则。没有 OVS控制室的指令就是一张废纸没有控制室OVS 就是一堆不会思考的阀门只能按出厂设置傻转。所以OVS 的本质是OpenFlow 协议的忠实实现者。OpenFlow 就是控制室和阀门之间的“消防指令语言”。它定义了怎么描述一个数据包的特征Match 字段源IP、目的端口、VLAN ID…就像描述“起火点位置火势类型”怎么告诉阀门该做什么Action 字段转发到端口2、打上VLAN标签、丢弃、送控制室研判…就像“关闭东侧防火门启动西侧喷淋”怎么让阀门上报异常Upcall发现不认识的包立刻喊“报告这个包没见过怎么办”把包和元数据打包发给控制室。而这份笔记里反复出现的ovs-ofctl、ofproto、datapath全都是围绕这个核心角色展开的ovs-ofctl是你临时客串“控制室值班员”的工具用命令行直接下发指令比如ovs-ofctl add-flow br0 priority100,ip,nw_src10.0.0.1,actionsoutput:2ofproto是 OVS 内部的“指令翻译官”它接收 OpenFlow 协议包解析出 Match 和 Action再转成 OVS 自己能懂的内部结构比如struct rule和struct ofpactdatapath是最终站在一线的“阀门本阀”它在内核里高速运行拿着翻译好的指令流表项对每个飞过的数据包做毫秒级匹配与执行。提示新手最容易混淆的点是把ovs-vswitchd用户态守护进程当成“主脑”。其实它更像一个“调度中心翻译办公室”它从数据库ovsdb-server读配置跟控制器Controller聊天把高层指令翻译成底层动作再把动作下发给内核datapath执行。真正的“肌肉”和“反射弧”永远在datapath模块里。这也是为什么笔记从第3页就开始讲datapath初始化——因为那是数据真正开始流动的地方。2.1 四个核心组件就是 OVS 的「四肢躯干」缺一不可各司其职OVS 不是一个单体程序而是一套精密协作的组件组合。笔记第2页列出的ovs-vswitchd、ovsdb-server、ovs-vsctl、ovs-dpctl就是它的“心脏、大脑、手、脚”。理解它们的关系比死记函数名重要十倍组件官方定位新手白话版你在哪一步会用到它关键命令示例ovsdb-server轻量级配置数据库OVS 的“记忆中枢”所有桥bridge、端口port、控制器controller的配置都存在这里。它不干活只存档、响应查询。第一次安装 OVS 后它自动启动你几乎不用直接操作它。但ovs-vsctl的所有操作背后都在跟它通信。ovsdb-server --remotepunix:/var/run/db.sock启动命令通常由 systemd 管理ovs-vswitchd用户态主守护进程OVS 的“总调度长”它连接ovsdb-server读配置连接 Controller 接收 OpenFlow 指令再把指令翻译、下发给内核datapath。它是整个系统的神经中枢。你启动 OVS 服务时它就在后台默默运行。ovs-ofctl下发流表最终也是通过它触达内核。ovs-vswitchd --pidfile --detach启动命令ovs-vsctl数据库配置工具OVS 的“前台办事员”你所有“建桥、加端口、连控制器”的操作都用它。它不碰数据包只改数据库里的配置记录。创建第一个虚拟交换机时必用。比如ovs-vsctl add-br br0建桥、ovs-vsctl add-port br0 eth0把物理网卡加入桥。ovs-vsctl show查看当前所有配置拓扑ovs-dpctl内核 datapath 配置工具OVS 的“内核直连工程师”它绕过ovs-vswitchd直接跟内核datapath模块对话用于调试、查看底层状态。普通配置不用它但排查“为什么流表不生效”时它是救命稻草。当你发现ovs-ofctl dump-flows显示有流表但数据包就是不转发就要用它看内核里真实的流表和端口状态。ovs-dpctl show显示所有 datapath 实例、ovs-dpctl dump-flows显示内核 datapath 中的真实流表注意ovs-ofctlOpenFlow 控制工具和ovs-appctl进程控制工具没列在上表因为它们是“临时工”。ovs-ofctl是你代替 Controller 下发指令的“遥控器”ovs-appctl是你给ovs-vswitchd进程发内部命令的“对讲机”比如ovs-appctl dpif/show查看 datapath 详细信息。它们不参与日常配置但在调试时高频出现。2.2 为什么必须分“用户态”和“内核态”——性能与灵活性的生死平衡这是新手读源码时最大的认知鸿沟为什么 OVS 要搞这么复杂把逻辑拆成ovs-vswitchd用户态和datapath内核态两部分直接全写在内核里不行吗答案关乎一个残酷事实Linux 内核追求稳定和安全绝不允许任何可能拖慢网络转发的“复杂逻辑”常驻其中。想象一下一个数据包以 10Gbps 速度涌入每秒数百万个包。如果每个包都要在内核里做复杂的 OpenFlow 规则匹配涉及多字段、掩码、跳转表、还要跟用户态进程通信、甚至触发 Python 脚本……内核早就崩了。OVS 的设计哲学是把“快”的事交给内核把“聪明”的事留给用户态。内核datapath只做三件事且必须极快收包从网卡驱动拿到 skbsocket buffer提 Key用ovs_flow_key_extract()快速提取包的关键特征源/目的 MAC/IP/端口等生成一个紧凑的sw_flow_key结构查流表 执行 Action用这个 Key在哈希表里极速查找匹配项找到就执行预设动作如OVS_ACTION_ATTR_OUTPUT转发到端口。这整个过程目标是在微秒级完成。所以datapath代码极度精简避免锁、避免内存分配、避免函数调用栈过深。笔记第3.1.3节讲的flow_lookup()和masked_flow_lookup()核心就是优化这个查找——用 mask cache 避免重复计算用分段哈希桶减少冲突。用户态ovs-vswitchd做所有“慢”但必要的事解析 OpenFlow 协议支持多个版本处理 TLV 编码维护复杂的流表管理超时、统计、优先级排序与 Controller 保持长连接、处理心跳、同步状态当datapath查不到匹配项Miss接收 upcall 上来的包进行深度分析xlate生成新流表项并下发回内核处理各种高级特性QoS、隧道封装GRE/VXLAN、采样sFlow。这些事可以慢一点毫秒级但必须灵活、可扩展、易调试。用户态天然支持动态加载、日志、调试器 attach而内核模块一旦出错就是 panic。所以当你看到笔记里ovs_dp_upcall()函数第3.1.8节把包发给用户态不要觉得是“失败了”这恰恰是 OVS 的核心智慧用内核的“快”兜底基础转发用用户态的“活”支撑业务创新。两者通过 Netlink一种高效的内核-用户态通信机制无缝衔接。这也是为什么笔记第3.1.2节强调genl_family注册——那是内核为datapath开的“专用快递通道”。2.3 从零搭建你的第一个 OVS 环境三步验证确认你已站在起点光说不练假把式。现在我们用最简方式亲手搭一个最小可用的 OVS 环境并验证datapath是否真在工作。这不是为了生产而是为了建立“手感”——当你亲眼看到数据包被 OVS 拦截、匹配、转发那份抽象感就落地了。步骤 1安装与基础检查2分钟在 Ubuntu/Debian 系统上推荐 20.04执行# 安装 OVS包含所有组件 sudo apt update sudo apt install openvswitch-switch openvswitch-common # 启动服务ovsdb-server 和 ovs-vswitchd 会自动启动 sudo systemctl start openvswitch-switch # 验证服务状态 sudo systemctl status openvswitch-switch # ✅ 应看到 active (exited) 或 active (running)步骤 2创建桥并添加端口1分钟# 创建一个名为 br0 的虚拟交换机bridge sudo ovs-vsctl add-br br0 # 查看当前所有桥应看到 br0 sudo ovs-vsctl show # 添加一个“内部端口”类似一个虚拟网卡可配 IP sudo ovs-vsctl add-port br0 br0-internal -- set interface br0-internal typeinternal # 给这个内部端口配 IP让它能 ping 通 sudo ip addr add 192.168.100.1/24 dev br0-internal sudo ip link set br0-internal up # 查看 br0 的端口状态 sudo ovs-ofctl show br0 # ✅ 应看到类似 LOCAL(br0-internal): addr:aa:bb:cc:dd:ee:ff 的输出步骤 3注入第一条流表见证数据流动3分钟这才是关键我们手动下发一条最简单的流表让所有进入 br0 的 IP 包都从br0-internal端口转发出去即“泛洪”到本机# 查看 br0 当前流表初始为空 sudo ovs-ofctl dump-flows br0 # ❌ 输出应为空无流表 # 下发第一条流表匹配所有 IP 包priority100动作是 output:1端口1 LOCAL sudo ovs-ofctl add-flow br0 priority100,ip,actionsoutput:1 # 再次查看流表确认已写入 sudo ovs-ofctl dump-flows br0 # ✅ 应看到类似 cookie0x0, duration10.1s, table0, n_packets0, ... 的一行 # 验证从本机 ping 自己触发流表匹配 ping -c 3 192.168.100.1 # ✅ 应看到 3 个包全部成功64 bytes from 192.168.100.1... # 关键验证看内核 datapath 是否真收到了这条流表 sudo ovs-dpctl dump-flows # ✅ 应看到类似 in_port(1),eth(),ip(), actions:1 的输出这就是 datapath 里真实运行的流表。逻辑说明ovs-ofctl add-flow命令本质是向ovs-vswitchd发送 OpenFlowOFPT_FLOW_MOD消息。ovs-vswitchd解析后通过 Netlink 将流表项struct sw_flow写入内核datapath的哈希桶。ovs-dpctl dump-flows直接读取内核内存所以它显示的是“真相”。而ovs-ofctl dump-flows读的是ovs-vswitchd内存中的缓存有时会有延迟。新手第一次看到ovs-dpctl输出和ovs-ofctl一致那种“啊它真的在跑”的顿悟感就是入门的临门一脚。3. 第一个必须读懂的源码片段ovs_flow_key_extract()—— 数据包的「身份证」是怎么生成的前面我们用ping验证了流表生效但那个ip匹配到底是怎么工作的它凭什么说这个包是“IP 包”这就引出了 OVS 最核心的环节Key 提取Key Extraction。笔记第3.1.3节提到的ovs_flow_key_extract()函数就是这个环节的入口。它不关心包的内容只负责从原始数据包skb里精准、高效地抠出一组标准化的字段组成一个sw_flow_key结构。这个结构就是 datapath 流表匹配的唯一依据相当于数据包的“身份证”。为什么必须抠出这些特定字段因为 OpenFlow 的 Match 字段如nw_src,tp_dst是协议定义的OVS 必须把网络栈里分散在不同层次的字段统一映射到这个结构里。比如MAC 地址在以太网帧头L2IP 地址在 IP 包头L3端口号在 TCP/UDP 包头L4VLAN ID 在 802.1Q 标签里L2.5。ovs_flow_key_extract()就是那个“全栈解析器”它按顺序扫描 skb根据协议类型层层解包把需要的字段填进sw_flow_key的对应位置。笔记第9页的struct sw_flow_key图就是这张身份证的模板。3.1 白话解读sw_flow_key结构一张数据包的「标准简历」笔记第9页的结构体初看密密麻麻但拆开就是一份清晰的“包简历”。我们只聚焦最常用的几个字段用生活化语言解释struct sw_flow_key { struct { uint8_t src[ETH_ALEN]; // 【教育背景】本科毕业院校源MAC地址6字节 uint8_t dst[ETH_ALEN]; // 【教育背景】硕士毕业院校目的MAC地址6字节 uint16_t tci; // 【附加证书】是否持有VLAN证书tci的低12位就是VLAN ID uint16_t type; // 【专业方向】主修专业0x0800IP, 0x86DDIPv6, 0x8100VLAN } eth; // 以太网层信息 struct { uint8_t proto; // 【核心技能】精通协议6TCP, 17UDP, 1ICMP uint8_t tos; // 【工作态度】服务类型TOS影响QoS优先级 uint8_t ttl; // 【职业寿命】生存时间TTL每经过一个路由器减1 uint32_t src; // 【家庭住址】老家IPIPv4源地址 uint32_t dst; // 【现居地址】现住址IPIPv4目的地址 } ipv4; // IPv4层信息如果是IPv6对应ipv6结构 struct { uint16_t src; // 【联系方式】手机号源端口 uint16_t dst; // 【联系方式】微信ID目的端口 } tp; // 传输层信息TCP/UDP端口 uint32_t recirc_id; // 【内部工号】循环ID用于OVS内部多阶段处理高级特性 uint16_t in_port; // 【入职部门】从哪个端口进来的如端口1br0-internal };关键点sw_flow_key是一个扁平化、固定长度的结构。它不存储原始包数据只存关键索引值。这样做的好处是流表匹配时CPU 只需比较几个整数src,dst,in_port速度极快。而ovs_flow_key_extract()的任务就是确保无论包是来自物理网卡、虚拟网卡tap/veth、还是隧道VXLAN都能被准确“翻译”成这份标准简历。3.2 动手验证用tcpdump抓包对照sw_flow_key看“简历”生成过程理论不如眼见为实。我们用tcpdump抓一个ping包再用ovs-dpctl查看 datapath 如何把它“翻译”成 Key# 步骤1在 br0-internal 端口抓包监听我们刚创建的内部端口 sudo tcpdump -i br0-internal -n -c 2 icmp # ✅ 会看到类似192.168.100.1 192.168.100.1: ICMP echo request (id12345, seq1) # 记下这个包的源/目的IP都是192.168.100.1、ICMP类型8 # 步骤2清空现有流表确保干净环境 sudo ovs-ofctl del-flows br0 # 步骤3下发一条精确匹配此 ping 包的流表只匹配ICMP sudo ovs-ofctl add-flow br0 priority200,icmp,nw_src192.168.100.1,nw_dst192.168.100.1,actionsoutput:1 # 步骤4再次 ping触发流表匹配 ping -c 1 192.168.100.1 # 步骤5查看 datapath 中实际匹配的 Key核心 sudo ovs-dpctl dump-flows | grep -A 5 icmp # ✅ 输出类似 # in_port(1),eth(),ip(),icmp(),nw_src192.168.100.1,nw_dst192.168.100.1, actions:1 # 这就是 datapath 从抓到的包里用 ovs_flow_key_extract() 提取出的 Key # 对比 tcpdump 输出源IP192.168.100.1目的IP192.168.100.1协议icmp对应proto1——完全吻合参数说明ovs-dpctl dump-flows的输出中in_port(1)是输入端口br0-internal 的编号eth()表示匹配任意以太网帧ip()表示匹配 IP 包icmp()表示匹配 ICMP 协议nw_src/nw_dst就是sw_flow_key.ipv4.src/dst字段。你看到的每一个字段都是ovs_flow_key_extract()从原始 skb 里精准抠出来的。这就是源码笔记的价值它告诉你dump-flows里显示的不是魔法而是ovs_flow_key_extract()这个函数一行行 C 代码执行的结果。3.3 常见问题排查为什么我的流表“看起来匹配”但包就是不转发这是新手踩坑率最高的问题。现象、原因、解决我们一条条拆解现象 1ovs-ofctl dump-flows显示有流表ovs-dpctl dump-flows却为空原因流表只写入了ovs-vswitchd的用户态缓存但未成功下发到内核datapath。常见于ovs-vswitchd进程崩溃、或datapath模块未正确加载。解决# 1. 检查 ovs-vswitchd 是否存活 sudo systemctl status openvswitch-switch # 2. 检查内核模块是否加载 lsmod | grep openvswitch # ✅ 应看到 openvswitch, nf_conntrack, nf_defrag_ipv6 等 # 3. 强制重载 datapath 模块谨慎会中断网络 sudo modprobe -r openvswitch sudo modprobe openvswitch sudo systemctl restart openvswitch-switch现象 2ovs-dpctl dump-flows显示流表但ping无响应ovs-appctl dpif/show显示n_misses0未命中原因流表的in_port匹配错了。ovs-ofctl add-flow默认匹配所有端口但ovs-dpctl dump-flows显示的in_port(1)是 datapath 内部端口编号不是ovs-vsctl show里看到的端口名。解决# 查看 datapath 端口真实编号 sudo ovs-dpctl show # ✅ 输出类似 # systemovs-system: hit:0 missed:0 lost:0 # port 0: ovs-system (internal) -- 这是LOCAL端口编号0 # port 1: br0-internal (internal) -- 这是我们加的端口编号1 # 所以流表必须明确指定 in_port1 sudo ovs-ofctl add-flow br0 priority200,in_port1,icmp,actionsoutput:1现象 3流表匹配成功n_packets0但包被丢弃ovs-appctl dpif/show显示n_dropped0原因Action 动作无效。最常见的是output:2但端口2不存在或未启用。解决# 1. 查看所有端口编号 sudo ovs-dpctl show # 2. 确保 Action 中的端口号存在且 UP sudo ip link show br0-internal | grep state # ✅ 应看到 state UP # 3. 用最保守的 Action 测试output:1本端口回环 sudo ovs-ofctl add-flow br0 priority300,ip,actionsoutput:1 ping -c 1 192.168.100.1 # 应成功现象 4ovs-dpctl dump-flows显示流表但tcpdump -i any抓不到包原因包被datapath处理后直接在内核里转发了没有经过用户态协议栈any接口抓不到。这是正常行为验证改用tcpdump -i br0-internal抓内部端口或tcpdump -i eth0如果你把物理网卡加入了 br0。4. 从“能跑”到“真懂”避坑指南——新手读 OVS 源码必踩的 4 个深坑读源码不是翻字典而是一场充满陷阱的探险。我第一次跟着这份笔记读datapath初始化时在dp_init()函数里卡了整整两天就因为掉进了下面这些坑。现在把血泪经验总结成 4 条帮你绕开弯路坑 1死磕module_init(dp_init)却忽略了datapath的“双重身份”现象在datapath.c里找到dp_init()看到register_pernet_device(ovs_net_ops)就以为初始化完了但后续ovs_vport_receive()收不到包。原因datapath模块有两个初始化入口module_init(dp_init)注册 Netlink family让内核知道“有 OVS 这个服务”pernet_operations的init函数ovs_net_init为每个网络命名空间network namespace创建独立的datapath实例。这才是真正干活的初始化笔记第3.1.2节只提了前者后者藏在ovs_net_ops结构体里。解决// 在 datapath.c 中找到 ovs_net_ops 定义 static struct pernet_operations ovs_net_ops { .init ovs_net_init, // 真正的初始化函数 .exit ovs_net_exit, .id ovs_net_id, .size sizeof(struct ovs_net), }; // 进入 ovs_net_init()你会看到 // - 分配全局的 flow_table流表哈希桶 // - 初始化 genl_familyNetlink 通信 // - 注册 vport 类型如 netdev, internal // 这才是 datapath “活过来”的时刻。教训module_init只是“注册上岗”pernet init才是“分配工位”。读初始化必须两条线一起跟。坑 2把ovs_flow_key_extract()当成“万能解析器”却不知它有“短路逻辑”现象给一个带 VLAN 的包下发vlan_tci100的流表但dump-flows显示vlan_tci0匹配失败。原因ovs_flow_key_extract()有严格的协议栈解析顺序。它先看以太网帧头如果type字段是0x8100VLAN才会继续解析 VLAN 标签把tci填入sw_flow_key.eth.tci。但如果包是0x0800IP它就直接跳过 VLAN 解析tci保持为 0。VLAN 标签必须在以太网帧头里且 type 正确才能被识别。解决确保发送包的设备如veth对启用了 VLAN 协议sudo ip link add link eth0 name eth0.100 type vlan id 100或用ovs-ofctl强制添加 VLANsudo ovs-ofctl add-flow br0 priority100,actionspush_vlan:0x8100,set_field:100-vlan_vid,output:2。坑 3对着sw_flow_key结构体找字段却忘了“字段存在性”由mask决定现象流表写了nw_src10.0.0.1但dump-flows显示nw_src0.0.0.0/0匹配总是失败。原因sw_flow_key里的字段只是“容器”真正决定哪些字段参与匹配的是sw_flow_mask掩码。笔记第3.1.4节的struct sw_flow_mask结构体就是用来标记“哪些位需要比较”。如果mask里nw_src对应的位是 0那么key.nw_src的值再大也没用匹配时会被忽略。解决# 查看当前流表的完整 mask需要 debug 版本 sudo ovs-appctl dpif/show | grep -A 10 mask # 或用更直观的方式下发流表时显式指定 mask sudo ovs-ofctl add-flow br0 priority100,ip,nw_src10.0.0.1/255.255.255.255,actionsoutput:1 # /255.255.255.255 就是告诉 OVSnw_src 字段必须全匹配mask 全 1。坑 4在ovs-vswitchd里找datapath交互却不知道dpif是“中间人”现象想搞懂ovs-vswitchd怎么把流表发给内核但在vswitchd/目录下找不到netlink相关代码。原因ovs-vswitchd和datapath之间隔着一个抽象层叫dpifDatapath Interface。笔记第2节提到的ofproto-dpif就是ofproto层调用dpif的接口而dpif的具体实现如dpif_netlink才真正封装了 Netlink 通信。vswitchd/目录下只有dpif的调用lib/dpif-netlink.c里才有netlink的 send/receive 逻辑。解决读vswitchd/bridge.c里的bridge_reconfigure()找到ofproto_create()进入ofproto-dpif.c找到dpif_operate()调用最终跳转到lib/dpif-netlink.c的dpif_netlink_operate()这里就是sendmsg()发 Netlink 消息的地方。血泪经验OVS 的分层太本文还有配套的精品资源点击获取