Open vSwitch 内核 datapath actions 执行流程深度解析

写这篇之前,我先说说踩坑背景。有次某 SDN 项目里控制器下发的流表明明没问题,但流量就是不通,tcpdump 抓包能看到包进了宿主机,却死活找不到从 OVS 出去的痕迹。最后一条条删内核 datapath 里的 flow,才意识到是 actions 里有一个不起眼的 drop 分支把包吃了。

后来我反复确认过很多次:Open vSwitch 的数据通路能不能扛住线上流量,百分之七八十取决于 flow 匹配后的 actions 执行链路。这条链路藏在 Linux 内核模块 openvswitch 里,用户态配置再漂亮,落到 datapath 就是一张掩码流表加一串 nlattr actions。这篇文章我就把 datapath 路径上 actions 的处理流程扒开讲,从内核侧的执行主循环、各 action 分派再到 recirc 和 conntrack 这类绕来绕去但必须搞清楚的机制,最后给排查思路。适合做 OVS 运维、研究 SDN 转发面、或者刚入门想搞懂“下发的 flow 究竟在内核里干了什么”的同行参考。

1. 为什么要单独把 actions 拎出来看

1.1 慢路径与 datapath 的分工逻辑

OVS 的数据包处理分两条线。第一条是慢路径:数据包匹配不到任何现有 flow 时,内核通过 netlink 把包头甚至整个包送到用户态的 vswitchd,由 OpenFlow 流水线按流表一路走下去,算出完整动作序列,再决定是直接执行还是把新 flow 安装回内核。第二条就是今天的主角 datapath:数据包到达后直接在内核态做掩码匹配,命中就拿预编译好的 actions 列表逐条执行,一条路走到黑,根本不经过用户态。

这条分工逻辑的本质是“尽量把转发决策下沉到最快路径”,只有第一次或保活类流量才付出慢路径的解析成本。我在排查问题时一般先区分流量走的是哪条路:ovs-appctl dpif/dump-flows能看到 datapath 命中的 flow,而ovs-appctl ofproto/trace能模拟慢路径决策。两者对照很多时候一眼就能看出是决策正确但 actions 没生效,还是压根没走到 datapath。

1.2 为什么 actions 值得单独研究

很多从 OpenFlow 配置入手的人会误以为下发的规则里写了什么,内核就会原样执行什么。实际上 OpenFlow 的动作只是“意图”,用户态 ofproto 层会把它翻译、拆分、补充成 datapath 里一条条OVS_ACTION_ATTR_*属性。比如 OpenFlow 里的 goto table 在 datapath 里可能变成一串 recirc 标记,group bucket 则可能被展开成多个 output action。翻译后的 actions 才是内核真正 qsort 执行的家伙,这块逻辑瞎改会直接导致包被发错口、循环封装甚至内核 panic。所以研究 datapath 的 actions 处理流程,本质上是在理解 OVS 控制面到转发面之间的那条“翻译走廊”。

1.3 包处理过程中 actions 的角色定位

可以把 datapath 的包处理拆成两个阶段:匹配阶段和执行阶段。匹配阶段用sw_flow_key加掩码去哈希表里找 flow;执行阶段拿到 flow 里存的acts指针和长度,遍历执行。无论匹配阶段多么高效,只要 actions 执行阶段有瓶颈或错误,整体转发性能都会被拖垮。尤其云网络场景里网卡多队列、隧道叠加同一套 OVS,actions 列表动辄包含 10 条以上动作,一个包被重复 output、recirc、重新封装都是常态,性能压力全在这块。

2. actions 在内核里长什么样

2.1 netlink 属性的物理形态

用户态下发 actions 时使用的载体是 netlink 属性(nlattr)。每个 action 的属性头是struct nlattr,由类型字段和长度字段组成,负载则是具体的动作参数。比如OVS_ACTION_ATTR_OUTPUT的负载就是 4 字节的端口号,OVS_ACTION_ATTR_SET的负载则是被包裹的ovs_key_*结构,里面携带要修改的字段值。正因如此,do_execute_actions循环时才会用nla_type(a)区分动作、用nla_data(a)取参数。

值得留意的是,内核要求所有 action 属性按 4 字节对齐,且每个 action 的长度包含头本身。实际分析问题时我习惯用ovs-dpctl dump-flows看 flow 的 actions 输出,它输出的正是这些 nlattr 解包后的文本形式,比如set(eth(src=00:11:22:33:44:55)),tnl_push(...),output(3)。看到这串东西,你心里就得能映射出它是一连串的 nlattr 块,而不是一串字符串。

2.2 内核侧 action 编译器到执行者的映射

datapath 执行 actions 的入口是ovs_execute_actions(),真正干事的循环体是do_execute_actions()。这段代码就是一个大 switch,按nla_type(a)分派到各自处理函数。我通常会直接打开源码net/openvswitch/actions.c,边看边对号入座。下表是我自己梳理的常见 action 类型到处理函数的对照,排查时很有用:

action 类型处理函数效果
OVS_ACTION_ATTR_OUTPUTdo_output从指定端口发出,drop 端口编号则丢包
OVS_ACTION_ATTR_USERSPACEovs_dp_upcall复制/转发包到用户态,同时可携带 userdata
OVS_ACTION_ATTR_PUSH_VLANpush_vlan压入 VLAN TCI,更新 key 和 skb
OVS_ACTION_ATTR_POP_VLANpop_vlan弹出 VLAN 头
OVS_ACTION_ATTR_SET / SET_MASKEDset_action / set_masked_action修改 L2~L4 字段,支持掩码
OVS_ACTION_ATTR_PUSH_MPLSpush_mpls压入 MPLS 标签
OVS_ACTION_ATTR_POP_MPLSpop_mpls弹出 MPLS 标签并生成新 eth header
OVS_ACTION_ATTR_SAMPLEsample_action按概率复制一份包走子 action
OVS_ACTION_ATTR_RECIRCovs_dp_process_packet用新 recirc_id 重新进入 datapath 流程
OVS_ACTION_ATTR_CTovs_ct_execute交给连接跟踪子系统处理
OVS_ACTION_ATTR_CT_CLEAR直接清除 skb 的 ct 状态清除连接跟踪标记
OVS_ACTION_ATTR_METERovs_meter_execute执行限速策略
OVS_ACTION_ATTR_TRUNCexecute_trunc_action截断包到指定长度后继续
OVS_ACTION_ATTR_HASHexecute_hash_action计算 hashing 并填到字段或 skb 元数据
OVS_ACTION_ATTR_DROPexecute_drop_action直接丢包
OVS_ACTION_ATTR_PUSH_ETH / POP_ETHpush_eth / pop_eth用于 shim 头处理等场景

这张表不用死记,重点是形成条件反射:看到 flow 里的 actions 字符串,就要能判断内核会对这个包做什么。

2.3 掩码匹配下的多头联动

datapath 的 flow 是带掩码的 megaflow,查找时是把包解析出的 key 和 flow 的 mask 做按位与,再比较是否等于 flow 的 key。一旦命中,flow 里保存的 actions 就原样执行。这个机制决定了 actions 的“作用对象”是整包,而不仅仅是 flow 匹配的那几个字段。举个例子,一条 flow 匹配eth_type(0x0800),actions 却是set(tp_dst=8080),output(1),即使匹配字段没包含 TCP,执行 set 时只要协议字段和 skb 支持,仍然会改端口号。理解这一点对排查“为什么别的服务端口也被改了”很有帮助。

3. actions 执行主链路逐个拆解

3.1 数据包进入 datapath 的入口

一个包进入 OVS 的路径有两条。物理口收包时,网卡驱动走netif_receive_skb,OVS 注册的 rx_handler 被调用,经过netdev_frame_hook→ovs_vport_receive→ovs_dp_process_packet;另一条是用户态主动下发,比如慢路径处理完的动作列表需要通过OVS_PACKET_CMD_EXECUTE执行,最终也汇聚到ovs_execute_actions→do_execute_actions。不管哪条入口,后续都会抽取 key、查表、执行 actions。

入口处比较隐蔽的坑是 vport 类型不同,收到的 skb 形态也不同。物理网卡和 tap 设备进来的是普通 skb,gre/vxlan/geneve 进来的则可能带着外层头的 skb。OVS 在ovs_flow_key_extract阶段会区分 tunnel metadata,把这些信息塞进 key。如果你在 actions 里做隧道操作,就要格外留意内外层信息是否已经解析干净,否则经常会出现明明加进去了却发不出去的怪事。

3.2 flow 查找:执行 actions 前的最后一道闸

ovs_dp_process_packet里查表发生在执行 actions 之前。它叫ovs_flow_tbl_lookup_stats,用 mask 数组和桶索引快速定位 flow。查找失败会触发 upcall,把包送到用户态;查找成功则拿到flow和stats,更新 hit 计数,然后进入ovs_execute_actions。这里我需要提醒:有时候你ovs-dpctl dump-flows能看到 flow,但包就是不走这条 flow,问题多半出在 mask 覆盖范围上,比如 mask 太宽把包匹配到了另一个 flow 上。

flow 结构里acts不是简单数组,它是struct sw_flow_actions,内部存着一个 nlattr 序列的总长度和指针。执行前内核会克隆这个 actions 结构,避免并发执行时被修改,也方便递归调用时维护引用计数。这也是为什么 datapath 流表里 action 列表可以安全地被多个 CPU 并发读。

3.3 主循环 do_execute_actions 的行为逻辑

do_execute_actions是 actions 执行的灵魂。它接收 dp、skb、key、attr 首地址和总长度,在一层循环里不断nla_next滑向下一个 action。每执行完一个分支都会检查 err,一旦出错就中断整个 action 串。这意味着同一 flow 前面的 action 成功后,后面 action 出错造成的结果不是“这部分生效”,而是整个包被丢弃并返回错误。我见过因set_action不支持某字段导致整个 action 链中断的情况,管控面下发时偶尔会遇到类型不匹配的动作组合,排错时要把报错日志和 dmesg 一起看。

具体流程我简化成下面这段示意代码,改的只是核心分支:

// net/openvswitch/actions.c 简化示意 static int do_execute_actions(struct datapath *dp, struct sk_buff *skb, struct sw_flow_key *key, const struct nlattr *attr, int len) { const struct nlattr *a; int rem = len; for (a = attr; rem > 0; a = nla_next(a, &rem)) { int err = 0; switch (nla_type(a)) { case OVS_ACTION_ATTR_OUTPUT: err = do_output(dp, skb, nla_get_u32(a), key); break; case OVS_ACTION_ATTR_USERSPACE: err = ovs_dp_upcall(dp, skb, key, a, OVS_PACKET_CMD_ACTION); break; case OVS_ACTION_ATTR_SET: err = set_action(skb, key, nla_data(a), nla_len(a), false); break; case OVS_ACTION_ATTR_PUSH_VLAN: err = push_vlan(skb, nla_data(a)); if (!err) key->eth.vlan.tci = ...; // 同步 key 中的 vlan 状态 break; case OVS_ACTION_ATTR_RECIRC: err = ovs_dp_process_packet(skb, key, nla_data(a), nla_len(a)); break; case OVS_ACTION_ATTR_CT: err = ovs_ct_execute(dp, skb, key, nla_data(a), nla_len(a)); break; case OVS_ACTION_ATTR_SAMPLE: err = sample_action(dp, skb, key, a, nla_len(a)); break; case OVS_ACTION_ATTR_METER: err = ovs_meter_execute(dp, skb, key, nla_get_u32(a)); break; } if (err) return err; } return 0; }

这段代码的逻辑一句话总结就是:从头到尾遍历 nlattr 串,按类型分派,谁出错就整体停。实际内核代码里分支比这多不少,比如OVS_ACTION_ATTR_HASH在早期版本直接跳过,后续版本才落地完整实现。所以我写这段是因为它的“遍历 + 分派”骨架是所有排障的基础。

3.4 组合执行示例:一条 set+output 的真实反应

光讲函数太抽象,走一个常见组合。假设 flow 的 actions 是set(eth(src=00:00:00:00:00:01)),output(5)。实际执行时:

  1. 循环第一项OVS_ACTION_ATTR_SET,set_action 解析 nlattr 里的ovs_key_eth,把源 MAC 写进 skb 的 MAC header,同时更新 flow key 里的 eth.src。
  2. 循环第二项OVS_ACTION_ATTR_OUTPUT,do_output 用端口号 5 查 vport,调ovs_vport_send,对虚拟口是直接dev_queue_xmit,对隧道口则是先封装再发送。
  3. 执行完毕,函数返回,这个包从端口 5 出去,源 MAC 已被改写。

这个过程中最容易被忽略的是set_action更新 key 的“同步性”。因为后续 action 可能依赖修改后的字段,比如 output 后的用户态 upcall 会把新 key 一并带上。若 set 和 key 不同步,用户态看到的字段仍是旧的,排查时很难定位到“改没改上”这层问题。datapath 对 key 的更新大多由各 action 分支自行完成,这也是为什么 action 顺序对最终行为影响极大。

4. 高级机制:recirc、conntrack 与隧道封装

4.1 recirc:让包重新排队再走一遍 datapath

第一次接触 recirc 的人普遍懵:一个包执行 actions 执行着执行着,怎么又回到流程起点?recirc 的诞生是因为 OpenFlow 流水线的多级流表和 datapath 的快速表结构天然不同。datapath 的 flow 只匹配一组字段,而 OpenFlow 需要根据前一组动作结果(比如 VLAN 改完后、学习表项插入后)再做下一级决策。于是 OVS 把“中间态”编码成一个 recirc_id,当 action 执行到OVS_ACTION_ATTR_RECIRC时,内核会带上这个 recirc_id 重新进入ovs_dp_process_packet,再次查表。

查表时,recirc_id 是作为一个 metadata 维度参与匹配的。这也解释了为什么 datapath dump 里经常能看到recirc_id(0x1),in_port(...),eth(...)这类特征。若你发现某条 flow 命中数一直是零,但下一跳 flow 命中数在涨,多半就是 recirc 把它转过去了。我实际排查多级 QoS 或安全组时,最痛苦的就是 recirc 链路上某一个 flow 被删或者 action 没配对,流量就凭空消失,这时顺着recirc_id逐个 dump 是唯一思路。

4.2 conntrack action 的两步式交互

OVS_ACTION_ATTR_CT是 ovs_ct_execute 的入口,它把 skb 连接到内核自身连接跟踪框架,根据 zone 和 key 里的五元组查找连接状态。比较关键的是ct_action执行完不一定只有一个包出来:当它检测到反向响应或者需要 NAT 时,会克隆出多个 skb,各自继续执行后续 actions。所以你会看到一条ct(zone=1,commit),recirc(...)的 flow,执行 conntrack 后没多久出现新的 recirc 分支,再走一遍流表根据ct_state决定放行还是丢弃。

线上排查 conntrack 问题时,我习惯先看ovs-appctl dpctl/dump-flows里的 ct_state 部分,再检查conntrack -L确认连接是否建立。CT 动作和 set 动作顺序也有讲究:必须先执行ct的 commit 让状态落库,再执行后续依赖 ct_mark 的动作,否则状态读不到。曾经加白名单时把ct(zone=1)放在set(ct_mark=1)后面,结果怎么都不生效,就是这条顺序反了。

4.3 隧道动作的封装与解封装路径

OVS 支持 vxlan、geneve、gre 等隧道时,action 里会直接出现tnl_push或tnl_pop。tnl_push不是单独的一种 action 类型,它通常嵌套在OVS_ACTION_ATTR_ENCAP或者以vport特殊端口的形式实现。OVS 做法是:隧道口也是一个 vport,当do_output往隧道口发包时,调vport->ops->send,在封装函数里把外层 IP/UDP 头补出来。这个过程会克隆原 skb,且可能涉及分片、GSO 等处理。

这个路径上的常见故障是 MTU 不匹配:action 里没显式处理分片,大包进入隧道后被中间链路静默丢弃,表现为 ping 小包通、大包不通。我处理这类问题最快的办法是ovs-dpctl dump-flows看隧道口 flow 有没有显示tnl_push(...)参数,再结合 ping with DF 标记排除三层 MTU 问题。

5. 排障与性能管理实战技巧

5.1 一表看懂 datapath 排障命令集

排查 actions 问题时,命令别乱敲,跟着链路走。我一般按这个顺序做:

现象命令目的
流量断开,怀疑 datapath flow 问题ovs-dpctl dump-flows看全部内核 flow 和各 actions 命中计数
想知道包匹配到哪条 flowovs-appctl ofproto/trace从 OpenFlow 侧 trace,看 downcall 到 datapath 的结果
datapath 有大量 missovs-appctl dpif/upcall_stats看 upcall 类型分布,定位是否 miss 爆增
数据包被 drop 了ovs-appctl ofproto/trace加-drop找到丢弃 flow 和具体 drop 的 action
包到了物理口但没从 OVS 出去tcpdump +ovs-appctl dpif/dump-flows对比包特征与 flow 匹配,锁定 action 执行问题

上述命令的核心思路是双视角验证:一个视角是“决策时怎么想”,另一个视角是“内核里怎么做”。两者对照,绝大多数 actions 问题可以定位到具体某一条 flow。

5.2 常见症状与内核动作的对应关系

实际运维中,以下几个症状几乎每个用 OVS 的人都遇到过,背后原因也高度集中在 action 执行链路:

  • 症状一:流量时通时不通,ovs-dpctl dump-flows里 hit count 持续增长但包没出去。多半是 output 端口配置不一致,或者端口对应 vport 的 send 函数报错。此时看 dmesg 或统计的错误计数。
  • 症状二:某类包全部被丢弃,ofproto/trace显示命中了某个 drop flow,但 OpenFlow 逻辑里不该丢。大概率是 controller 下发了dropaction 的 high-priority flow,或 datapath 里 recirc 分支错配。直接ovs-dpctl del-flow试探能快速区分。
  • 症状三:MPLS/VLAN 多层标签叠加后行为异常。这是 push/pop 系列 action 对 key 和 skb 同步维护不到位的结果。排查时逐级去掉 push,看哪一层动作引发了错误。
  • 症状四:开启 conntrack 后流量中断且偶发 panic 报告。多半是 CT action 和OVS_ACTION_ATTR_RECIRC之间的组合在 mask 上没配对,导致同一连接正反向包走了不同 flow。检查ovs-appctl dpif/dump-flows中 recirc_id 是否一致非常关键。

5.3 性能隐患从 actions 数量入手

actions 执行是串行的,越多越慢。一条 flow 如果包含 20 条 action,每包都需要遍历。这里容易被忽略的是OVS_ACTION_ATTR_SAMPLE:sample 内部包含一个子 action 列表,执行时会走到递归调用,如果 sample 嵌套再 sample,性能损耗不容小觑。监控上泉能反映问题的是 PMD 线程 CPU 和 hit/miss 比例,命令如下:

ovs-appctl dpif-netdev/pmd-stats-show ovs-appctl dpif-netdev/flow-stats-show

如果 hit/miss 比例异常,很多 miss 触发的 upcall 才是真正瓶颈,而不是 actions 本身。极端情况下少量 action 的 flow 反而比大量 action 的 flow 更“贵”,因为 miss 把大量包送到用户态排队。

6. 写在最后的一些经验

我翻 action 处理流程的次数越多,越觉得 datapath 里这些 nlattr 就是连接 OpenFlow 世界和内核转发世界的那根细线。很多人调 OVS 停留在怎么配置,不看内核模块实际行为,遇到疑难问题时就会很被动。我的习惯是:每改动一类 action,就立刻用ovs-appctl ofproto/trace走一遍慢路径,再用ovs-dpctl dump-flows对比 datapath 最终产物,坚持下来能省很多排查时间。

如果之后想继续往深钻,建议跟着源码把actions.c里 set 动作的掩码语义、recirc 的 key 保存逻辑、以及 DPIF 层 action 翻译这三大块吃透,它们基本能覆盖绝大多数生产问题的分析方法。

相关新闻

OVS datapath actions执行流程详解:从内核源码到性能调优

OVS datapath actions执行流程详解:从内核源码到性能调优

先说一个我前阵子实际遇到的问题。某次排查一个bond口上的流量分流不均,流表里明明配了group,但实际转发效果和预期差了很多。一开始怀疑是hash算法的问题,翻来覆去看用户态流表,后来直接把内核datapath路径上的action执行流程从头…

2026/10/20 2:58:48 阅读更多 →
3、内存 - 计算机品牌排行榜

3、内存 - 计算机品牌排行榜

基于2026年全球DRAM原厂产能、消费级内存模组市场占有率及用户综合口碑,当前电脑内存品牌排行榜如下,‌金士顿以全球领先的市占率稳居第一‌,一线电竞品牌在超频性能上表现突出,国产高性价比品牌近年市场份额增长迅猛。 1. 金士顿…

2026/10/20 2:57:47 阅读更多 →
Java部署YOLOv8模型量化提速:从FP32到INT8完整实践

Java部署YOLOv8模型量化提速:从FP32到INT8完整实践

前阵子做个工业质检项目,跑的是YOLOv8检测模型,部署环境锁定在Java后端。代码写完之后发现推理速度一直上不去,GPU利用率不高,内存带宽倒是快吃满了。一开始怀疑是不是ONNX导出有问题,后来一条条排查,瓶颈最…

2026/10/20 2:57:47 阅读更多 →

最新新闻

Cursor 详细使用指南:TaoToken 统一 Key 接入与 AI 辅助编程调试实战

Cursor 详细使用指南:TaoToken 统一 Key 接入与 AI 辅助编程调试实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 3:49:13 阅读更多 →
别急着拿它给短剧配音:音色版权、多角色与长文本的三个隐性坑

别急着拿它给短剧配音:音色版权、多角色与长文本的三个隐性坑

别急着拿它给短剧配音:音色版权、多角色与长文本的三个隐性坑 【免费下载链接】drama-3 项目地址: https://ai.gitcode.com/hf_mirrors/fishaudio/drama-3 当一款开源 TTS 模型被社区评测顶到"开放权重语音竞技场"榜首,和 ElevenLabs、…

2026/10/20 3:49:13 阅读更多 →
电脑主机改造成服务器:硬件差异、稳定性与避坑指南

电脑主机改造成服务器:硬件差异、稳定性与避坑指南

先别急着回答“能”或者“不能”,我把话放在这里:普通电脑主机确实能改造成服务器,而且成本可以压得很低。但我见过太多人,把自己的旧电脑折腾成“服务器”之后,没跑两个月就放弃了,原因就四个字&#xff1…

2026/10/20 3:49:13 阅读更多 →
CFRP约束型钢再生混凝土短柱ABAQUS复现:参数设置与曲线调试全解析

CFRP约束型钢再生混凝土短柱ABAQUS复现:参数设置与曲线调试全解析

做CFRP约束型钢再生混凝土短柱的论文复现,最折磨人的往往不是建模本身,而是材料参数取值和相互作用设置。你从论文里抄参数,原封不动搬到ABAQUS里,结果曲线跟原文对不上,大概率不是模型搭错,是CDP损伤参数、…

2026/10/20 3:49:13 阅读更多 →
物理开路与奇点:文明权的终局博弈,一场底层逻辑推演

物理开路与奇点:文明权的终局博弈,一场底层逻辑推演

最近我一直在琢磨一个特别上头的问题:如果物理学出现本质层面的突破,会不会直接改写文明的命运?这个问题的民间版本,就是标题里那八个字——物理开路、奇点、文明权、终局博弈。先声明一句,我就是一个业余物理爱好者&a…

2026/10/20 3:49:13 阅读更多 →
电商客服与导购智能体合并设计:意图识别、工具调用与知识库实践

电商客服与导购智能体合并设计:意图识别、工具调用与知识库实践

做客服类智能体这几年,我的电脑里存过三版方案。第一版是规则加菜单按钮,用户点两下就烦了;第二版是纯大模型问答,什么都能聊,但一问到订单和售后就露馅;第三版才是真正跑通业务价值的——把电商客服导购智…

2026/10/20 3:48:13 阅读更多 →

日新闻

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →
ESP32舵机控制指南:原理、多路驱动与避坑实战

ESP32舵机控制指南:原理、多路驱动与避坑实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →
位移法实现一阶低通滤波:单片机ADC采样降噪实战

位移法实现一阶低通滤波:单片机ADC采样降噪实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/19 10:02:04 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/19 17:32:41 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/20 2:50:50 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/19 2:54:50 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/19 9:10:22 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 12:16:16 阅读更多 →